summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sw/CppunitTest_sw_layoutwriter.mk1
-rw-r--r--sw/qa/extras/layout/layout.cxx948
2 files changed, 949 insertions, 0 deletions
diff --git a/sw/CppunitTest_sw_layoutwriter.mk b/sw/CppunitTest_sw_layoutwriter.mk
index 37a142ec61ac..eb25e0258fd8 100644
--- a/sw/CppunitTest_sw_layoutwriter.mk
+++ b/sw/CppunitTest_sw_layoutwriter.mk
@@ -44,6 +44,7 @@ $(eval $(call gb_CppunitTest_use_externals,sw_layoutwriter,\
$(eval $(call gb_CppunitTest_set_include,sw_layoutwriter,\
-I$(SRCDIR)/sw/inc \
-I$(SRCDIR)/sw/source/core/inc \
+ -I$(SRCDIR)/sw/source/uibase/inc \
-I$(SRCDIR)/sw/qa/extras/inc \
$$(INCLUDE) \
))
diff --git a/sw/qa/extras/layout/layout.cxx b/sw/qa/extras/layout/layout.cxx
index 0b5630361e49..fc17a36500f9 100644
--- a/sw/qa/extras/layout/layout.cxx
+++ b/sw/qa/extras/layout/layout.cxx
@@ -15,6 +15,9 @@
#include <officecfg/Office/Common.hxx>
#include <comphelper/scopeguard.hxx>
#include <unotools/syslocaleoptions.hxx>
+#include <fmtanchr.hxx>
+#include <fmtfsize.hxx>
+#include <wrtsh.hxx>
static char const DATA_DIRECTORY[] = "/sw/qa/extras/layout/data/";
@@ -25,6 +28,9 @@ class SwLayoutWriter : public SwModelTestBase
public:
void testRedlineFootnotes();
+ void testRedlineFlysInBody();
+ void testRedlineFlysInHeader();
+ void testRedlineFlysInFootnote();
void testTdf116830();
void testTdf116925();
void testTdf117028();
@@ -46,6 +52,9 @@ public:
CPPUNIT_TEST_SUITE(SwLayoutWriter);
CPPUNIT_TEST(testRedlineFootnotes);
+ CPPUNIT_TEST(testRedlineFlysInBody);
+ CPPUNIT_TEST(testRedlineFlysInHeader);
+ CPPUNIT_TEST(testRedlineFlysInFootnote);
CPPUNIT_TEST(testTdf116830);
CPPUNIT_TEST(testTdf116925);
CPPUNIT_TEST(testTdf117028);
@@ -214,6 +223,945 @@ void SwLayoutWriter::testRedlineFootnotes()
CheckRedlineFootnotesHidden();
}
+void SwLayoutWriter::testRedlineFlysInBody()
+{
+ // currently need experimental mode
+ Resetter _([]() {
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::ExperimentalMode::set(false, pBatch);
+ return pBatch->commit();
+ });
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::ExperimentalMode::set(true, pBatch);
+ pBatch->commit();
+
+ loadURL("private:factory/swriter", nullptr);
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
+ SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+ SwRootFrame* pLayout(pWrtShell->GetLayout());
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ pWrtShell->Insert("foo");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("bar");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("baz");
+ SfxItemSet flySet(pDoc->GetAttrPool(),
+ svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{});
+ SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
+ pWrtShell->SttDoc(false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+ flySet.Put(anchor);
+ SwFormatFrameSize size(ATT_MIN_SIZE, 1000, 1000);
+ flySet.Put(size); // set a size, else we get 1 char per line...
+ SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
+ CPPUNIT_ASSERT(pFly != nullptr);
+ // move inside fly
+ pWrtShell->GotoFly(pFly->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
+ pWrtShell->Insert("abc");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("def");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("ghi");
+
+ lcl_dispatchCommand(mxComponent, ".uno:TrackChanges", {});
+ // delete redline inside fly
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
+ pWrtShell->Delete();
+
+ pWrtShell->SttEndDoc(true); // note: SttDoc actually moves to start of fly?
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
+ pWrtShell->Delete();
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (i == 1) // secondly, try with different anchor type
+ {
+ anchor.SetType(RndStdIds::FLY_AT_PARA);
+ SwPosition pos(*anchor.GetContentAnchor());
+ pos.nContent.Assign(nullptr, 0);
+ anchor.SetAnchor(&pos);
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ xmlDocPtr pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
+ "paraPropsNodeIndex", "6");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
+ "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
+ "ahi");
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+
+ { // show: nothing is merged
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
+ "a");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
+ "bc");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
+ "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
+ "def");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
+ "g");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
+ "hi");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
+ }
+
+ // anchor to 2nd (deleted) paragraph
+ pWrtShell->SttDoc();
+ pWrtShell->Down(false, 1);
+ anchor.SetType(RndStdIds::FLY_AT_CHAR);
+ anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (i == 1) // secondly, try with different anchor type
+ {
+ anchor.SetType(RndStdIds::FLY_AT_PARA);
+ SwPosition pos(*anchor.GetContentAnchor());
+ pos.nContent.Assign(nullptr, 0);
+ anchor.SetAnchor(&pos);
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ xmlDocPtr pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
+
+ { // hide: no anchored object shown
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+
+ { // show: nothing is merged
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
+ "a");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
+ "bc");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
+ "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
+ "def");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
+ "g");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
+ "hi");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
+ }
+
+ // anchor to 3rd paragraph
+ pWrtShell->EndDoc();
+ anchor.SetType(RndStdIds::FLY_AT_CHAR);
+ anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (i == 1) // secondly, try with different anchor type
+ {
+ anchor.SetType(RndStdIds::FLY_AT_PARA);
+ SwPosition pos(*anchor.GetContentAnchor());
+ pos.nContent.Assign(nullptr, 0);
+ anchor.SetAnchor(&pos);
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ xmlDocPtr pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
+ "paraPropsNodeIndex", "6");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
+ "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
+ "ahi");
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+
+ { // show: nothing is merged
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
+ "a");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
+ "bc");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
+ "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
+ "def");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
+ "g");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
+ "hi");
+ }
+}
+
+void SwLayoutWriter::testRedlineFlysInHeader()
+{
+ // currently need experimental mode
+ Resetter _([]() {
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::ExperimentalMode::set(false, pBatch);
+ return pBatch->commit();
+ });
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::ExperimentalMode::set(true, pBatch);
+ pBatch->commit();
+
+ loadURL("private:factory/swriter", nullptr);
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
+ SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+ SwRootFrame* pLayout(pWrtShell->GetLayout());
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ pWrtShell->ChangeHeaderOrFooter("Default Style", /*bHeader*/ true, /*bOn*/ true, false);
+ CPPUNIT_ASSERT(
+ pWrtShell
+ ->IsInHeaderFooter()); // assume this is supposed to put cursor in the new header...
+ pWrtShell->Insert("foo");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("bar");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("baz");
+ SfxItemSet flySet(pDoc->GetAttrPool(),
+ svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{});
+ SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
+ pWrtShell->SttDoc(false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+ flySet.Put(anchor);
+ SwFormatFrameSize size(ATT_MIN_SIZE, 1000, 1000);
+ flySet.Put(size); // set a size, else we get 1 char per line...
+ SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
+ CPPUNIT_ASSERT(pFly != nullptr);
+ // move inside fly
+ pWrtShell->GotoFly(pFly->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
+ pWrtShell->Insert("abc");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("def");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("ghi");
+
+ lcl_dispatchCommand(mxComponent, ".uno:TrackChanges", {});
+ // delete redline inside fly
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
+ pWrtShell->Delete();
+
+ pWrtShell->GotoHeaderText();
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
+ pWrtShell->Delete();
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (i == 1) // secondly, try with different anchor type
+ {
+ anchor.SetType(RndStdIds::FLY_AT_PARA);
+ SwPosition pos(*anchor.GetContentAnchor());
+ pos.nContent.Assign(nullptr, 0);
+ anchor.SetAnchor(&pos);
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ xmlDocPtr pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/merged",
+ "paraPropsNodeIndex", "11");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
+ "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "ahi");
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+
+ { // show: nothing is merged
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "a");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
+ "Portion", "bc");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
+ "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
+ "Portion", "def");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
+ "Portion", "g");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
+ "Portion", "hi");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
+ }
+
+ // anchor to 2nd (deleted) paragraph
+ pWrtShell->SttDoc();
+ pWrtShell->Down(false, 1);
+ anchor.SetType(RndStdIds::FLY_AT_CHAR);
+ anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (i == 1) // secondly, try with different anchor type
+ {
+ anchor.SetType(RndStdIds::FLY_AT_PARA);
+ SwPosition pos(*anchor.GetContentAnchor());
+ pos.nContent.Assign(nullptr, 0);
+ anchor.SetAnchor(&pos);
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ xmlDocPtr pXmlDoc = parseLayoutDump();
+ // now the frame has no Text portion? not sure why it's a 0-length one first and now none?
+ // assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_PARA");
+ // assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
+
+ { // hide: no anchored object shown
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+
+ { // show: nothing is merged
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "a");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
+ "Portion", "bc");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
+ "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
+ "Portion", "def");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
+ "Portion", "g");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
+ "Portion", "hi");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
+ }
+
+ // anchor to 3rd paragraph
+ pWrtShell->EndDoc();
+ anchor.SetType(RndStdIds::FLY_AT_CHAR);
+ anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (i == 1) // secondly, try with different anchor type
+ {
+ anchor.SetType(RndStdIds::FLY_AT_PARA);
+ SwPosition pos(*anchor.GetContentAnchor());
+ pos.nContent.Assign(nullptr, 0);
+ anchor.SetAnchor(&pos);
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ xmlDocPtr pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/merged",
+ "paraPropsNodeIndex", "11");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
+ "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "ahi");
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+
+ { // show: nothing is merged
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "a");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
+ "Portion", "bc");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
+ "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
+ "Portion", "def");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
+ "Portion", "g");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
+ "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
+ "Portion", "hi");
+ }
+}
+
+void SwLayoutWriter::testRedlineFlysInFootnote()
+{
+ // currently need experimental mode
+ Resetter _([]() {
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::ExperimentalMode::set(false, pBatch);
+ return pBatch->commit();
+ });
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::ExperimentalMode::set(true, pBatch);
+ pBatch->commit();
+
+ loadURL("private:factory/swriter", nullptr);
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
+ SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
+ SwRootFrame* pLayout(pWrtShell->GetLayout());
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ pWrtShell->InsertFootnote("");
+ CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote());
+
+ SfxItemSet flySet(pDoc->GetAttrPool(),
+ svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{});
+ SwFormatFrameSize size(ATT_MIN_SIZE, 1000, 1000);
+ flySet.Put(size); // set a size, else we get 1 char per line...
+ SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
+ anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+ flySet.Put(anchor);
+ // first fly is in first footnote that will be deleted
+ /* SwFrameFormat const* pFly1 =*/pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
+ pWrtShell->Insert("quux");
+
+ pWrtShell->SttEndDoc(false);
+
+ pWrtShell->InsertFootnote("");
+ CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote());
+ pWrtShell->Insert("foo");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("bar");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("baz");
+
+ pWrtShell->SttDoc(false);
+ CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote());
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+ flySet.Put(anchor);
+ // second fly is in second footnote that is not deleted
+ SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
+ CPPUNIT_ASSERT(pFly != nullptr);
+ // move inside fly
+ pWrtShell->GotoFly(pFly->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
+ pWrtShell->Insert("abc");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("def");
+ pWrtShell->SplitNode(false);
+ pWrtShell->Insert("ghi");
+
+ lcl_dispatchCommand(mxComponent, ".uno:TrackChanges", {});
+ // delete redline inside fly
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
+ pWrtShell->Delete();
+
+ // pWrtShell->GotoFlyAnchor(); // sigh... why, now we're in the body...
+ pWrtShell->SttEndDoc(false);
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ pWrtShell->GotoFootnoteText();
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
+ pWrtShell->Delete();
+ pWrtShell->EndSelect(); // ?
+ // delete first footnote
+ pWrtShell->SttEndDoc(true);
+ pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
+ pWrtShell->Delete();
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (i == 1) // secondly, try with different anchor type
+ {
+ anchor.SetType(RndStdIds::FLY_AT_PARA);
+ SwPosition pos(*anchor.GetContentAnchor());
+ pos.nContent.Assign(nullptr, 0);
+ anchor.SetAnchor(&pos);
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ xmlDocPtr pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType", "POR_FTN");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "2");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
+ "7");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/merged",
+ "paraPropsNodeIndex", "17");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "ahi");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
+ "POR_FTNNUM");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "2");
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+
+ { // show: nothing is merged
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType", "POR_FTN");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType", "POR_FTN");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "quux");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
+ "POR_FTNNUM");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "a");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
+ "Portion", "bc");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
+ "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
+ "Portion", "def");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
+ "Portion", "g");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
+ "Portion", "hi");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
+ "POR_FTNNUM");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
+ }
+
+ // anchor to 2nd (deleted) paragraph
+ pWrtShell->SttEndDoc(false);
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ pWrtShell->GotoFootnoteText();
+ pWrtShell->Down(false, 1);
+ anchor.SetType(RndStdIds::FLY_AT_CHAR);
+ anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (i == 1) // secondly, try with different anchor type
+ {
+ anchor.SetType(RndStdIds::FLY_AT_PARA);
+ SwPosition pos(*anchor.GetContentAnchor());
+ pos.nContent.Assign(nullptr, 0);
+ anchor.SetAnchor(&pos);
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ xmlDocPtr pXmlDoc = parseLayoutDump();
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType", "POR_FTN");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "2");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
+ "7");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
+ "POR_FTNNUM");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "2");
+
+ { // hide: no anchored object shown
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+
+ { // show: nothing is merged
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType", "POR_FTN");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType", "POR_FTN");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "quux");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
+ "POR_FTNNUM");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
+ "POR_FTNNUM");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "a");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
+ "Portion", "bc");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
+ "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
+ "Portion", "def");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
+ "Portion", "g");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
+ "Portion", "hi");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
+ }
+
+ // anchor to 3rd paragraph
+ pWrtShell->EndDoc();
+ pWrtShell->SttEndDoc(false);
+ pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
+ pWrtShell->GotoFootnoteText();
+ pWrtShell->EndDoc();
+ anchor.SetType(RndStdIds::FLY_AT_CHAR);
+ anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (i == 1) // secondly, try with different anchor type
+ {
+ anchor.SetType(RndStdIds::FLY_AT_PARA);
+ SwPosition pos(*anchor.GetContentAnchor());
+ pos.nContent.Assign(nullptr, 0);
+ anchor.SetAnchor(&pos);
+ pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
+ }
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ xmlDocPtr pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType", "POR_FTN");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "2");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
+ "7");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/merged",
+ "paraPropsNodeIndex", "17");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "ahi");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
+ "POR_FTNNUM");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "2");
+
+ lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
+ CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+
+ { // show: nothing is merged
+ xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
+ xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
+ CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
+ xmlXPathFreeObject(pXmlObj);
+ }
+
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType", "POR_FTN");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType", "POR_FTN");
+ assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "quux");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
+ "POR_FTNNUM");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
+ "POR_FTNNUM");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
+ "Portion", "a");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
+ "Portion", "bc");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
+ "nType", "POR_PARA");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
+ "Portion", "def");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
+ "Portion", "g");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
+ "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
+ "Portion", "hi");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType", "POR_TXT");
+ assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
+ }
+}
+
void SwLayoutWriter::testTdf116830()
{
SwDoc* pDoc = createDoc("tdf116830.odt");