sw/qa/uibase/shells/shells.cxx      |   31 +++++++++++++++++++++++++++++++
 sw/source/uibase/shells/textfld.cxx |   10 ++++++++++
 2 files changed, 41 insertions(+)

New commits:
commit a178a2ac6df8dc63a7ab8d4a19b90ae8a17baca4
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Jan 2 14:45:53 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Jan 2 18:26:32 2023 +0000

    sw UI: fix crash on inserting a fieldmark inside a fieldmark
    
    Inserting a fieldmark using .uno:TextFormField, then entering into that
    fieldmark using the cursor, finally doing in insertion again using
    .uno:TextFormField resulted in a crash.
    
    The problem is that lcl_SetFieldMarks() uses 3
    IDocumentContentOperations().InsertString() calls to insert the field
    start/separator/end, but right after inserting the field start we
    already create an sw::InsertText hint, which works with an inconsistent
    string (the start is already inserted but not the separator / end).
    
    Fix the problem by just not allowing the insertion of fieldmarks inside
    fieldmarks on the UI: these are meant to be read-only for the user, so
    fieldmark insertion is OK to be not working, as long as a clear error
    message is provided.
    
    An alternative approach would be to insert the inner fieldmark in a way
    similar to how import filters can do it, but that would be more work.
    
    Change-Id: I7d1a7c638b179fd9149ccdc47215329e3433b6e5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144947
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index a6603984afbb..2f89720cf570 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -501,6 +501,37 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, 
testUpdateBookmarks)
     CPPUNIT_ASSERT_EQUAL(OUString("Anew result 1Cnew result 2E"), aActual);
 }
 
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertFieldmarkReadonly)
+{
+    // Given a document with a fieldmark, the cursor inside the fieldmark:
+    createSwDoc();
+    uno::Sequence<css::beans::PropertyValue> aArgs = {
+        comphelper::makePropertyValue("FieldType", 
uno::Any(OUString(ODF_UNHANDLED))),
+        comphelper::makePropertyValue("FieldCommand", uno::Any(OUString("my 
command"))),
+        comphelper::makePropertyValue("FieldResult", uno::Any(OUString("my 
result"))),
+    };
+    dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+    SwDoc* pDoc = getSwDoc();
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    SwCursor* pCursor = pWrtShell->GetCursor();
+    pCursor->SttEndDoc(/*bSttDoc=*/true);
+    pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, 
/*bBasicCall=*/false);
+
+    // When trying to insert an inner fieldmark:
+    // Without the accompanying fix in place, this test would have crashed.
+    dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+
+    // Then make sure the read-only content refuses to accept that inner 
fieldmark, so we still have
+    // just one:
+    size_t nActual = 0;
+    IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
+    for (auto it = rIDMA.getFieldmarksBegin(); it != rIDMA.getFieldmarksEnd(); 
++it)
+    {
+        ++nActual;
+    }
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), nActual);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/shells/textfld.cxx 
b/sw/source/uibase/shells/textfld.cxx
index 12cc13a15bd2..aad7d0891bd9 100644
--- a/sw/source/uibase/shells/textfld.cxx
+++ b/sw/source/uibase/shells/textfld.cxx
@@ -719,6 +719,16 @@ FIELD_INSERT:
                 aFieldCode = pFieldCode->GetValue();
             }
 
+            if (rSh.HasReadonlySel())
+            {
+                // Inform the user that the request has been ignored.
+                auto xInfo = std::make_shared<weld::GenericDialogController>(
+                    GetView().GetFrameWeld(), 
"modules/swriter/ui/inforeadonlydialog.ui",
+                    "InfoReadonlyDialog");
+                weld::DialogController::runAsync(xInfo, [](sal_Int32 
/*nResult*/) {});
+                break;
+            }
+
             
rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, 
nullptr);
             // Don't update the layout after inserting content and before 
deleting temporary
             // text nodes.

Reply via email to