desktop/source/lib/init.cxx         |    3 +-
 sw/qa/uibase/shells/shells.cxx      |   30 ++++++++++++++++++++
 sw/qa/uibase/uno/uno.cxx            |   29 +++++++++++++++++++
 sw/source/uibase/shells/textfld.cxx |   10 ++++++
 sw/source/uibase/uno/loktxdoc.cxx   |   53 ++++++++++++++++++++++++++++++++++++
 5 files changed, 124 insertions(+), 1 deletion(-)

New commits:
commit 519ead63478a66f907c477dd15dba214d2b59f90
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jan 3 11:28:04 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Jan 5 07:11:15 2023 +0000

    sw, lok: implement a getCommandValues(Fields)
    
    There was no LOK API to get a list of all fields of a given type where
    the name matches a certain prefix.
    
    This is useful in case the API cilent wants to know what previously
    inserted refmarks were deleted by the user as part of deleting text
    content.
    
    Add a new getCommandValues(".uno:Fields") that returns the names of
    matching refmarks. Do not return the refmark text, assuming that would
    be updated by the API client anyway.
    
    In practice this is needed by Zotero in case it wants to model its
    citations with refmarks.
    
    (cherry picked from commit 3585d0414ffe08890856e5c09f453b9f566323df)
    
    Change-Id: Ie469253891896aa8ab00d434c9ab116adbe3864b
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144989
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Justin Luth <jl...@mail.com>

diff --git a/desktop/source/lib/init.cxx b/desktop/source/lib/init.cxx
index 617d5926dc0b..0c3be4b25743 100644
--- a/desktop/source/lib/init.cxx
+++ b/desktop/source/lib/init.cxx
@@ -5729,7 +5729,8 @@ static char* doc_getCommandValues(LibreOfficeKitDocument* 
pThis, const char* pCo
     static const std::initializer_list<std::u16string_view> vForward = {
         u"TextFormFields",
         u"SetDocumentProperties",
-        u"Bookmarks"
+        u"Bookmarks",
+        u"Fields"
     };
 
     if (!strcmp(pCommand, ".uno:LanguageStatus"))
diff --git a/sw/qa/uibase/uno/uno.cxx b/sw/qa/uibase/uno/uno.cxx
index 1664f18c5dda..41866636a969 100644
--- a/sw/qa/uibase/uno/uno.cxx
+++ b/sw/qa/uibase/uno/uno.cxx
@@ -214,6 +214,35 @@ CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetBookmarks)
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), 
aTree.get_child("bookmarks").count(""));
 }
 
+CPPUNIT_TEST_FIXTURE(SwUibaseUnoTest, testGetFields)
+{
+    // Given a document with a refmark:
+    createSwDoc();
+    uno::Sequence<css::beans::PropertyValue> aArgs = {
+        comphelper::makePropertyValue("TypeName", 
uno::Any(OUString("SetRef"))),
+        comphelper::makePropertyValue(
+            "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} 
RNDpyJknp173F"))),
+        comphelper::makePropertyValue("Content", 
uno::Any(OUString("mycontent"))),
+    };
+    dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
+
+    // When getting the refmarks:
+    tools::JsonWriter aJsonWriter;
+    OString 
aCommand(".uno:Fields?typeName=SetRef&namePrefix=ZOTERO_ITEM%20CSL_CITATION");
+    auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+    pXTextDocument->getCommandValues(aJsonWriter, aCommand);
+
+    // Then make sure we get the 1 refmark:
+    std::unique_ptr<char[], o3tl::free_delete> 
pJSON(aJsonWriter.extractData());
+    std::stringstream aStream(pJSON.get());
+    boost::property_tree::ptree aTree;
+    boost::property_tree::read_json(aStream, aTree);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - No such node (setRefs)
+    // i.e. the returned JSON was just empty.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), 
aTree.get_child("setRefs").count(""));
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/uno/loktxdoc.cxx 
b/sw/source/uibase/uno/loktxdoc.cxx
index fd6d05eef132..ffcd967a6496 100644
--- a/sw/source/uibase/uno/loktxdoc.cxx
+++ b/sw/source/uibase/uno/loktxdoc.cxx
@@ -34,6 +34,7 @@
 #include <IDocumentMarkAccess.hxx>
 #include <doc.hxx>
 #include <docsh.hxx>
+#include <fmtrfmrk.hxx>
 
 using namespace ::com::sun::star;
 
@@ -170,6 +171,53 @@ void GetBookmarks(tools::JsonWriter& rJsonWriter, 
SwDocShell* pDocShell,
         rJsonWriter.put("name", pMark->GetName());
     }
 }
+
+/// Implements getCommandValues(".uno:Fields").
+///
+/// Parameters:
+///
+/// - typeName: field type condition to not return all fields
+/// - namePrefix: field name prefix to not return all fields
+void GetFields(tools::JsonWriter& rJsonWriter, SwDocShell* pDocShell,
+               const std::map<OUString, OUString>& rArguments)
+{
+    OUString aTypeName;
+    {
+        auto it = rArguments.find("typeName");
+        if (it != rArguments.end())
+        {
+            aTypeName = it->second;
+        }
+    }
+    // See SwFieldTypeFromString().
+    if (aTypeName != "SetRef")
+    {
+        return;
+    }
+
+    OUString aNamePrefix;
+    {
+        auto it = rArguments.find("namePrefix");
+        if (it != rArguments.end())
+        {
+            aNamePrefix = it->second;
+        }
+    }
+
+    SwDoc* pDoc = pDocShell->GetDoc();
+    tools::ScopedJsonWriterArray aBookmarks = 
rJsonWriter.startArray("setRefs");
+    for (sal_uInt16 i = 0; i < pDoc->GetRefMarks(); ++i)
+    {
+        const SwFormatRefMark* pRefMark = pDoc->GetRefMark(i);
+        if (!pRefMark->GetRefName().startsWith(aNamePrefix))
+        {
+            continue;
+        }
+
+        tools::ScopedJsonWriterStruct aProperty = rJsonWriter.startStruct();
+        rJsonWriter.put("name", pRefMark->GetRefName());
+    }
+}
 }
 
 void SwXTextDocument::getCommandValues(tools::JsonWriter& rJsonWriter, const 
OString& rCommand)
@@ -179,6 +227,7 @@ void SwXTextDocument::getCommandValues(tools::JsonWriter& 
rJsonWriter, const OSt
     static constexpr OStringLiteral aTextFormFields(".uno:TextFormFields");
     static constexpr OStringLiteral 
aSetDocumentProperties(".uno:SetDocumentProperties");
     static constexpr OStringLiteral aBookmarks(".uno:Bookmarks");
+    static constexpr OStringLiteral aFields(".uno:Fields");
 
     INetURLObject aParser(OUString::fromUtf8(rCommand));
     OUString aArguments = aParser.GetParam();
@@ -214,6 +263,10 @@ void SwXTextDocument::getCommandValues(tools::JsonWriter& 
rJsonWriter, const OSt
     {
         GetBookmarks(rJsonWriter, m_pDocShell, aMap);
     }
+    else if (o3tl::starts_with(rCommand, aFields))
+    {
+        GetFields(rJsonWriter, m_pDocShell, aMap);
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 0881419f485727ac0d9e1e65be868645688578ce
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Jan 2 14:45:53 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Jan 5 07:11:05 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.
    
    (cherry picked from commit a178a2ac6df8dc63a7ab8d4a19b90ae8a17baca4)
    
    Change-Id: I7d1a7c638b179fd9149ccdc47215329e3433b6e5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/144980
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Justin Luth <jl...@mail.com>

diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index 9b2ecd1d1612..88324d12327e 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -439,6 +439,36 @@ 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:
+    SwDoc* pDoc = 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);
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    SwCursor* pCursor = pWrtShell->GetCursor();
+    pCursor->SttEndDoc(/*bSttDoc=*/true);
+    pWrtShell->Right(CRSR_SKIP_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 620ceff0fb14..7db07202b1b2 100644
--- a/sw/source/uibase/shells/textfld.cxx
+++ b/sw/source/uibase/shells/textfld.cxx
@@ -710,6 +710,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