sw/inc/cmdid.h                      |    1 
 sw/qa/uibase/shells/shells.cxx      |   45 ++++++++++++++++++++++++++++++
 sw/sdi/_textsh.sdi                  |    6 ++++
 sw/sdi/swriter.sdi                  |   14 +++++++++
 sw/source/uibase/shells/textfld.cxx |   54 ++++++++++++++++++++++++++++++++++++
 5 files changed, 120 insertions(+)

New commits:
commit c68d06dfa1498f862923eaddf3e5d247650a53d5
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Jan 10 15:40:34 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Tue Jan 10 21:08:51 2023 +0000

    sw: add a new .uno:DeleteTextFormFields UNO command
    
    Users sometimes want to "unlink" their citations, which means deleting
    the fieldmarks (if fieldmarks are used to represent citations, e.g.
    with Zotero), which means keeping the field result as-is, but removing
    the field metadata and the actual field start/seprator/end characters.
    
    Do this similar to .uno:TextFormFields, which can do an update of such
    fieldmarks, i.e. add the ability to filter for a certain type and field
    command prefix. This is meant to allow removal af all fieldmark that
    belongs to one one feature, e.g. Zotero.
    
    This is similar to 7765b442e13048f857fd7ee49ced1731caee297e (sw: add a
    new .uno:TextFormFields UNO command, 2022-11-28), but this is about
    deleting (the field commands, not the result), while that was about
    updating.
    
    The same for bookmarks & refmarks are not yet supported.
    
    Change-Id: I02548b030b1822f7b36d3bc5ff9553d728f065c2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145272
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/inc/cmdid.h b/sw/inc/cmdid.h
index bec1acbe5446..befe8e26d607 100644
--- a/sw/inc/cmdid.h
+++ b/sw/inc/cmdid.h
@@ -324,6 +324,7 @@ class SwUINumRuleItem;
 #define FN_EDIT_BOOKMARK        (FN_INSERT2 + 33 )  /* Bookmark */
 #define FN_UPDATE_BOOKMARKS (FN_INSERT2 + 34)
 #define FN_UPDATE_SECTIONS (FN_INSERT2 + 35)
+#define FN_DELETE_TEXT_FORMFIELDS (FN_INSERT2 + 36)
 
 // Region: Format
 #define FN_AUTOFORMAT_APPLY     (FN_FORMAT + 1 ) /* apply autoformat options */
diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx
index 8dbdee89267c..edfe255f4ad7 100644
--- a/sw/qa/uibase/shells/shells.cxx
+++ b/sw/qa/uibase/shells/shells.cxx
@@ -713,6 +713,51 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, 
testUpdateSections)
     CPPUNIT_ASSERT_EQUAL(OUString("new content"), aActualResult);
 }
 
+CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testDeleteFieldmarks)
+{
+    // Given a document with 2 fieldmarks:
+    createSwDoc();
+    {
+        uno::Sequence<css::beans::PropertyValue> aArgs = {
+            comphelper::makePropertyValue("FieldType", 
uno::Any(OUString(ODF_UNHANDLED))),
+            comphelper::makePropertyValue("FieldCommand",
+                                          uno::Any(OUString("ADDIN ZOTERO_ITEM 
old command 1"))),
+            comphelper::makePropertyValue("FieldResult", 
uno::Any(OUString("result 1"))),
+        };
+        dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+    }
+    {
+        uno::Sequence<css::beans::PropertyValue> aArgs = {
+            comphelper::makePropertyValue("FieldType", 
uno::Any(OUString(ODF_UNHANDLED))),
+            comphelper::makePropertyValue("FieldCommand",
+                                          uno::Any(OUString("ADDIN ZOTERO_ITEM 
old command 2"))),
+            comphelper::makePropertyValue("FieldResult", 
uno::Any(OUString("result 2"))),
+        };
+        dispatchCommand(mxComponent, ".uno:TextFormField", aArgs);
+    }
+
+    // When deleting those fieldmarks:
+    uno::Sequence<css::beans::PropertyValue> aArgs
+        = { comphelper::makePropertyValue("FieldType", 
uno::Any(OUString(ODF_UNHANDLED))),
+            comphelper::makePropertyValue("FieldCommandPrefix",
+                                          uno::Any(OUString("ADDIN 
ZOTERO_ITEM"))) };
+    dispatchCommand(mxComponent, ".uno:DeleteTextFormFields", aArgs);
+
+    // Then make sure that the document doesn't contain fields anymore:
+    SwDoc* pDoc = getSwDoc();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 0
+    // - Actual  : 2
+    // i.e. the fieldmarks were not deleted.
+    CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0),
+                         pDoc->getIDocumentMarkAccess()->getAllMarksCount());
+    SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+    pWrtShell->SttEndDoc(/*bStt=*/true);
+    SwCursor* pCursor = pWrtShell->GetCursor();
+    OUString aActual = pCursor->Start()->GetNode().GetTextNode()->GetText();
+    CPPUNIT_ASSERT_EQUAL(OUString("result 1result 2"), aActual);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/sdi/_textsh.sdi b/sw/sdi/_textsh.sdi
index f712ea376776..99f50c8e3b27 100644
--- a/sw/sdi/_textsh.sdi
+++ b/sw/sdi/_textsh.sdi
@@ -1820,6 +1820,12 @@ interface BaseText
         StateMethod = StateField ;
     ]
 
+    FN_DELETE_TEXT_FORMFIELDS
+    [
+        ExecMethod = ExecField ;
+        StateMethod = StateField ;
+    ]
+
     FN_PROTECT_FIELDS
     [
         ExecMethod = Execute ;
diff --git a/sw/sdi/swriter.sdi b/sw/sdi/swriter.sdi
index bc0c5456aef8..76939d94c03a 100644
--- a/sw/sdi/swriter.sdi
+++ b/sw/sdi/swriter.sdi
@@ -8330,6 +8330,20 @@ SfxVoidItem TextFormFields FN_UPDATE_TEXT_FORMFIELDS
     GroupId = SfxGroupId::Controls;
 ]
 
+SfxVoidItem DeleteTextFormFields FN_DELETE_TEXT_FORMFIELDS
+(SfxStringItem FieldType FN_PARAM_1, SfxStringItem FieldCommandPrefix 
FN_PARAM_2)
+[
+    AutoUpdate = TRUE,
+    FastCall = FALSE,
+    ReadOnlyDoc = FALSE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+
+    GroupId = SfxGroupId::Controls;
+]
+
 SfxVoidItem UpdateTextFormField FN_UPDATE_TEXT_FORMFIELD
 (SfxStringItem FieldType FN_PARAM_1, SfxStringItem FieldCommandPrefix 
FN_PARAM_2, SfxUnoAnyItem Field FN_PARAM_3)
 [
diff --git a/sw/source/uibase/shells/textfld.cxx 
b/sw/source/uibase/shells/textfld.cxx
index 71e57ba0ae47..7e10b7a8673d 100644
--- a/sw/source/uibase/shells/textfld.cxx
+++ b/sw/source/uibase/shells/textfld.cxx
@@ -933,6 +933,60 @@ FIELD_INSERT:
         
rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, 
nullptr);
     }
     break;
+    case FN_DELETE_TEXT_FORMFIELDS:
+    {
+        // This deletes all fieldmarks that match the provided field type & 
field command prefix.
+        OUString aFieldType;
+        const SfxStringItem* pFieldType = 
rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+        if (pFieldType)
+        {
+            aFieldType = pFieldType->GetValue();
+        }
+        OUString aFieldCommandPrefix;
+        const SfxStringItem* pFieldCommandPrefix = 
rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+        if (pFieldCommandPrefix)
+        {
+            aFieldCommandPrefix = pFieldCommandPrefix->GetValue();
+        }
+        
rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, 
nullptr);
+        rSh.StartAction();
+
+        IDocumentMarkAccess* pMarkAccess = 
rSh.GetDoc()->getIDocumentMarkAccess();
+        std::vector<sw::mark::IMark*> aRemovals;
+        for (auto it = pMarkAccess->getFieldmarksBegin(); it != 
pMarkAccess->getFieldmarksEnd(); ++it)
+        {
+            auto pFieldmark = dynamic_cast<sw::mark::IFieldmark*>(*it);
+            assert(pFieldmark);
+            if (pFieldmark->GetFieldname() != aFieldType)
+            {
+                continue;
+            }
+
+            auto itParam = pFieldmark->GetParameters()->find(ODF_CODE_PARAM);
+            if (itParam == pFieldmark->GetParameters()->end())
+            {
+                continue;
+            }
+
+            OUString aCommand;
+            itParam->second >>= aCommand;
+            if (!aCommand.startsWith(aFieldCommandPrefix))
+            {
+                continue;
+            }
+
+            aRemovals.push_back(pFieldmark);
+        }
+
+        for (const auto& pMark : aRemovals)
+        {
+            pMarkAccess->deleteMark(pMark);
+        }
+
+        rSh.EndAction();
+        
rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, 
nullptr);
+    }
+    break;
     case FN_PGNUMBER_WIZARD:
     {
         SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();

Reply via email to