sw/qa/uibase/shells/shells.cxx | 55 ++++++++++++++++++++++++++++++++++-- sw/source/core/crsr/bookmark.cxx | 20 +++++++++++++ sw/source/core/inc/bookmark.hxx | 1 sw/source/uibase/shells/basesh.cxx | 26 ++++++++++++++--- sw/source/uibase/shells/textfld.cxx | 16 +++++++--- 5 files changed, 107 insertions(+), 11 deletions(-)
New commits: commit 52ff5cf6c289bc187dc7987e86496a6c07e26ca3 Author: Pranam Lashkari <[email protected]> AuthorDate: Thu Jan 19 00:14:50 2023 +0530 Commit: Miklos Vajna <[email protected]> CommitDate: Tue Feb 7 08:44:07 2023 +0100 sw: send LOK call back on fieldmark deletion this helps with zotero when user deletes a fieldmark or use undo without this online will be unaware of any such changes made by user (cherry picked from commit 4ca01e91d72df3f69d8b5c7a4d6fddd863a396fc) Change-Id: I93cf102c20b3861140508aee5d81e65f5b9207ec diff --git a/sw/source/core/crsr/bookmark.cxx b/sw/source/core/crsr/bookmark.cxx index 2520e6312b79..b7e5b4a7850b 100644 --- a/sw/source/core/crsr/bookmark.cxx +++ b/sw/source/core/crsr/bookmark.cxx @@ -48,6 +48,7 @@ #include <LibreOfficeKit/LibreOfficeKitEnums.h> #include <rtl/strbuf.hxx> #include <strings.hrc> +#include <tools/json_writer.hxx> using namespace ::sw::mark; using namespace ::com::sun::star; @@ -562,6 +563,25 @@ namespace sw::mark m_aName = rName; } + TextFieldmark::~TextFieldmark() + { + SfxViewShell* pViewShell = SfxViewShell::Current(); + if (!pViewShell) + return; + + OUString fieldCommand; + (*GetParameters())[OUString(ODF_CODE_PARAM)] >>= fieldCommand; + tools::JsonWriter aJson; + aJson.put("commandName", ".uno:DeleteTextFormField"); + aJson.put("success", true); + { + auto result = aJson.startNode("result"); + aJson.put("DeleteTextFormField", fieldCommand); + } + + pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_UNO_COMMAND_RESULT, aJson.extractData()); + } + void TextFieldmark::InitDoc(SwDoc& io_rDoc, sw::mark::InsertMode const eMode, SwPosition const*const pSepPos) { diff --git a/sw/source/core/inc/bookmark.hxx b/sw/source/core/inc/bookmark.hxx index a349c9063b76..b4630b18701c 100644 --- a/sw/source/core/inc/bookmark.hxx +++ b/sw/source/core/inc/bookmark.hxx @@ -239,6 +239,7 @@ namespace sw::mark { { public: TextFieldmark(const SwPaM& rPaM, const OUString& rName); + ~TextFieldmark(); void InitDoc(SwDoc& io_rDoc, sw::mark::InsertMode eMode, SwPosition const* pSepPos) override; void ReleaseDoc(SwDoc& rDoc) override; commit f2a2eb6b1b3f09c1e547efee1436816e9c7571c3 Author: Miklos Vajna <[email protected]> AuthorDate: Tue Jan 17 11:38:14 2023 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Tue Feb 7 08:42:44 2023 +0100 sw: .uno:TextFormField: handle Endnote as a value for the Wrapper parameter This is similar to the fieldmark-in-footnote case, but here we need to make sure that the layout is calculated before the cursor attempts to jump to the endnote, otherwise the fieldmark will be inserted before the endnote anchor, not in the endnote body. The move of StartAction() / EndAction() calls can be done unconditionally, it's not a problem for the existing footnote case. (cherry picked from commit 43d80906c8693ca27c5b3077fbaa259df4004924) Change-Id: I772d27937456978ca6aa01148eff3163d8877208 diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx index 9325e18d34b0..d5dffc5e3d2e 100644 --- a/sw/qa/uibase/shells/shells.cxx +++ b/sw/qa/uibase/shells/shells.cxx @@ -40,6 +40,7 @@ #include <docsh.hxx> #include <ndtxt.hxx> #include <ftnidx.hxx> +#include <txtftn.hxx> /// Covers sw/source/uibase/shells/ fixes. class SwUibaseShellsTest : public SwModelTestBase @@ -960,6 +961,46 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertTextFormFieldFootnote) CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rFootnotes.size()); } +CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertTextFormFieldEndnote) +{ + // Given an empty document: + createSwDoc(); + SwDoc* pDoc = getSwDoc(); + + // When inserting an ODF_UNHANDLED fieldmark inside an endnote: + uno::Sequence<css::beans::PropertyValue> aArgs = { + comphelper::makePropertyValue("FieldType", uno::Any(OUString(ODF_UNHANDLED))), + comphelper::makePropertyValue("FieldCommand", + uno::Any(OUString("ADDIN ZOTERO_BIBL foo bar"))), + comphelper::makePropertyValue("FieldResult", uno::Any(OUString("result"))), + comphelper::makePropertyValue("Wrapper", uno::Any(OUString("Endnote"))), + }; + dispatchCommand(mxComponent, ".uno:TextFormField", aArgs); + + // Then make sure that the endnote is created: + SwFootnoteIdxs& rFootnotes = pDoc->GetFootnoteIdxs(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1 + // - Actual : 0 + // i.e. no endnote was inserted. + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rFootnotes.size()); + SwTextFootnote* pEndnote = rFootnotes[0]; + const SwFormatFootnote& rFormatEndnote = pEndnote->GetFootnote(); + CPPUNIT_ASSERT(rFormatEndnote.IsEndNote()); + // Also check that the endnote body contains the fieldmark: + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + pWrtShell->SttEndDoc(/*bStt=*/true); + pWrtShell->GotoFootnoteText(); + pWrtShell->EndOfSection(/*bSelect=*/true); + SwCursor* pCursor = pWrtShell->GetCursor(); + OUString aActual = pCursor->GetText(); + static sal_Unicode const aForbidden[] + = { CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP, CH_TXT_ATR_FIELDEND, 0 }; + aActual = comphelper::string::removeAny(aActual, aForbidden); + // Then this was empty: the fieldmark was inserted before the note anchor, not in the note body. + CPPUNIT_ASSERT_EQUAL(OUString("result"), aActual); +} + 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 61e99dd71731..073e0625a770 100644 --- a/sw/source/uibase/shells/textfld.cxx +++ b/sw/source/uibase/shells/textfld.cxx @@ -731,9 +731,6 @@ FIELD_INSERT: } rSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT_FORM_FIELD, nullptr); - // Don't update the layout after inserting content and before deleting temporary - // text nodes. - rSh.StartAction(); SwPaM* pCursorPos = rSh.GetCursor(); if(pCursorPos) @@ -758,8 +755,19 @@ FIELD_INSERT: { rSh.InsertFootnote(OUString()); } + else if (aWrapper == "Endnote") + { + // It's important that there is no Start/EndAction() around this, so the + // inner EndAction() triggers a layout update and the cursor can jump to the + // created SwFootnoteFrame. + rSh.InsertFootnote(OUString(), /*bEndNote=*/true); + } } + // Don't update the layout after inserting content and before deleting temporary + // text nodes. + rSh.StartAction(); + // Split node to remember where the start position is. bool bSuccess = rSh.GetDoc()->getIDocumentContentOperations().SplitNode( *pCursorPos->GetPoint(), false); @@ -802,9 +810,9 @@ FIELD_INSERT: std::pair<OUString, uno::Any>(ODF_CODE_PARAM, uno::Any(aFieldCode))); } } + rSh.EndAction(); } - rSh.EndAction(); rSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT_FORM_FIELD, nullptr); rSh.GetView().GetViewFrame()->GetBindings().Invalidate( SID_UNDO ); } commit 7d752d5f740c35d3318ac44d8112ddbaaff5b35c Author: Pranam Lashkari <[email protected]> AuthorDate: Sat Jan 7 02:39:38 2023 +0530 Commit: Miklos Vajna <[email protected]> CommitDate: Tue Feb 7 08:41:49 2023 +0100 sw, UpdateFields: update in sorted order This was using the order used by GetItemSurrogates() which can be hard to predict So it used to update field in uncertain ways Now it updates field in order of the fields in file (cherry picked from commit e65b27e79f177d27131479c46d089cad33df557b) Change-Id: I7fc39b476cae6ed6a7fb7186803d4205832d7a73 diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx index d15ef3813dd4..ef9c2a4c9ab8 100644 --- a/sw/source/uibase/shells/basesh.cxx +++ b/sw/source/uibase/shells/basesh.cxx @@ -805,10 +805,27 @@ bool UpdateFieldConents(SfxRequest& rReq, SwWrtShell& rWrtSh) SwDoc* pDoc = rWrtSh.GetDoc(); pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSBOOKMARK, nullptr); rWrtSh.StartAction(); + + std::vector<const SwFormatRefMark*> aRefMarks; + + for (sal_uInt16 i = 0; i < pDoc->GetRefMarks(); ++i) + { + aRefMarks.push_back(pDoc->GetRefMark(i)); + } + + std::sort(aRefMarks.begin(), aRefMarks.end(), + [](const SwFormatRefMark* pMark1, const SwFormatRefMark* pMark2) -> bool { + const SwTextRefMark* pTextRefMark1 = pMark1->GetTextRefMark(); + const SwTextRefMark* pTextRefMark2 = pMark2->GetTextRefMark(); + SwPosition aPos1(pTextRefMark1->GetTextNode(), pTextRefMark1->GetStart()); + SwPosition aPos2(pTextRefMark2->GetTextNode(), pTextRefMark2->GetStart()); + return aPos1 < aPos2; + }); + sal_uInt16 nFieldIndex = 0; - for (sal_uInt16 nRefMark = 0; nRefMark < pDoc->GetRefMarks(); ++nRefMark) + for (auto& pIntermediateRefMark : aRefMarks) { - auto pRefMark = const_cast<SwFormatRefMark*>(pDoc->GetRefMark(nRefMark)); + auto pRefMark = const_cast<SwFormatRefMark*>(pIntermediateRefMark); if (!pRefMark->GetRefName().startsWith(rNamePrefix)) { continue; commit f24800156488cb7a44600a574f93964999fa92e4 Author: Miklos Vajna <[email protected]> AuthorDate: Thu Jan 5 10:35:21 2023 +0100 Commit: Miklos Vajna <[email protected]> CommitDate: Tue Feb 7 08:40:55 2023 +0100 sw update of refmarks: fix handling of ignored refmarks As pointed out at <https://gerrit.libreoffice.org/c/core/+/145036/1#message-165c0282ace92160592c896c6867095d3558ee96>, it's not correct that UpdateFieldConents() uses a single index into both the provided fields/refmarks array and into the document's all refmarks array. We need a new index that counts the input fields/refmarks we got and which is not incremented for ignored refmarks. Extend the testcase to have 2 paragraphs in the document: the first paragraph has a refmark that is to be ignored and the second para has a refmark that is interesting to us. This makes the test fail. Then fix up UpdateFieldConents() to properly count how we iterate through all refmarks and the provided refmarks in parallel. (cherry picked from commit 471804e251b4e15b37a10920bd4b88b40f97b227) Change-Id: I1fabf5b29beeabe9e8a126f1662ca8830e5c4e20 diff --git a/sw/qa/uibase/shells/shells.cxx b/sw/qa/uibase/shells/shells.cxx index 98f371f90c45..9325e18d34b0 100644 --- a/sw/qa/uibase/shells/shells.cxx +++ b/sw/qa/uibase/shells/shells.cxx @@ -471,10 +471,20 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testInsertFieldmarkReadonly) CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmarks) { - // Given a document with a refmark: + // Given a document with two refmarks, one is not interesting the other is a citation: createSwDoc(); SwDoc* pDoc = getSwDoc(); uno::Sequence<css::beans::PropertyValue> aArgs = { + comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))), + comphelper::makePropertyValue("Name", uno::Any(OUString("some other old refmark"))), + comphelper::makePropertyValue("Content", uno::Any(OUString("some other old content"))), + }; + dispatchCommand(mxComponent, ".uno:InsertField", aArgs); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->SttEndDoc(/*bStt=*/false); + pWrtShell->SplitNode(); + pWrtShell->SttEndDoc(/*bStt=*/false); + aArgs = { comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))), comphelper::makePropertyValue( "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} old refmark"))), @@ -483,8 +493,6 @@ CPPUNIT_TEST_FIXTURE(SwUibaseShellsTest, testUpdateRefmarks) dispatchCommand(mxComponent, ".uno:InsertField", aArgs); // When updating that refmark: - SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); - pWrtShell->SttEndDoc(/*bStt=*/true); std::vector<beans::PropertyValue> aArgsVec = comphelper::JsonToPropertyValues(R"json( { "TypeName": { diff --git a/sw/source/uibase/shells/basesh.cxx b/sw/source/uibase/shells/basesh.cxx index e23d2414c305..d15ef3813dd4 100644 --- a/sw/source/uibase/shells/basesh.cxx +++ b/sw/source/uibase/shells/basesh.cxx @@ -805,6 +805,7 @@ bool UpdateFieldConents(SfxRequest& rReq, SwWrtShell& rWrtSh) SwDoc* pDoc = rWrtSh.GetDoc(); pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSBOOKMARK, nullptr); rWrtSh.StartAction(); + sal_uInt16 nFieldIndex = 0; for (sal_uInt16 nRefMark = 0; nRefMark < pDoc->GetRefMarks(); ++nRefMark) { auto pRefMark = const_cast<SwFormatRefMark*>(pDoc->GetRefMark(nRefMark)); @@ -813,11 +814,11 @@ bool UpdateFieldConents(SfxRequest& rReq, SwWrtShell& rWrtSh) continue; } - if (aFields.getLength() <= nRefMark) + if (nFieldIndex >= aFields.getLength()) { continue; } - comphelper::SequenceAsHashMap aMap(aFields[nRefMark]); + comphelper::SequenceAsHashMap aMap(aFields[nFieldIndex++]); auto aName = aMap["Name"].get<OUString>(); pRefMark->GetRefName() = aName;
