1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
10 #include <swmodeltestbase.hxx>
11 #include <unotest/bootstrapfixturebase.hxx>
12 #include <comphelper/propertysequence.hxx>
13 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
14 #include <com/sun/star/frame/DispatchHelper.hpp>
15 #include <com/sun/star/text/WrapTextMode.hpp>
16 #include <comphelper/scopeguard.hxx>
17 #include <unotools/syslocaleoptions.hxx>
18 #include <i18nlangtag/languagetag.hxx>
19 #include <vcl/event.hxx>
20 #include <vcl/scheduler.hxx>
21 #include <editeng/lrspitem.hxx>
22 #include <editeng/fontitem.hxx>
23 #include <editeng/fhgtitem.hxx>
24 #include <editeng/postitem.hxx>
25 #include <editeng/unolingu.hxx>
26 #include <fmtanchr.hxx>
27 #include <fmtfsize.hxx>
28 #include <fmtcntnt.hxx>
29 #include <wrtsh.hxx>
30 #include <edtwin.hxx>
31 #include <view.hxx>
32 #include <txtfrm.hxx>
33 #include <pagefrm.hxx>
34 #include <bodyfrm.hxx>
35 #include <sortedobjs.hxx>
36 #include <anchoredobject.hxx>
37 #include <ndtxt.hxx>
38 #include <frmatr.hxx>
39 #include <IDocumentSettingAccess.hxx>
40
41 static char const DATA_DIRECTORY[] = "/sw/qa/extras/layout/data/";
42
43 /// Test to assert layout / rendering result of Writer.
44 class SwLayoutWriter : public SwModelTestBase
45 {
46 protected:
47 void CheckRedlineFootnotesHidden();
48 void CheckRedlineSectionsHidden();
49 void CheckRedlineCharAttributesHidden();
50
51 SwDoc* createDoc(const char* pName = nullptr);
52 };
53
createDoc(const char * pName)54 SwDoc* SwLayoutWriter::createDoc(const char* pName)
55 {
56 if (!pName)
57 loadURL("private:factory/swriter", nullptr);
58 else
59 load(DATA_DIRECTORY, pName);
60
61 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
62 CPPUNIT_ASSERT(pTextDoc);
63 return pTextDoc->GetDocShell()->GetDoc();
64 }
65
lcl_dispatchCommand(const uno::Reference<lang::XComponent> & xComponent,const OUString & rCommand,const uno::Sequence<beans::PropertyValue> & rPropertyValues)66 static void lcl_dispatchCommand(const uno::Reference<lang::XComponent>& xComponent,
67 const OUString& rCommand,
68 const uno::Sequence<beans::PropertyValue>& rPropertyValues)
69 {
70 uno::Reference<frame::XController> xController
71 = uno::Reference<frame::XModel>(xComponent, uno::UNO_QUERY_THROW)->getCurrentController();
72 CPPUNIT_ASSERT(xController.is());
73 uno::Reference<frame::XDispatchProvider> xFrame(xController->getFrame(), uno::UNO_QUERY);
74 CPPUNIT_ASSERT(xFrame.is());
75
76 uno::Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
77 uno::Reference<frame::XDispatchHelper> xDispatchHelper(frame::DispatchHelper::create(xContext));
78 CPPUNIT_ASSERT(xDispatchHelper.is());
79
80 xDispatchHelper->executeDispatch(xFrame, rCommand, OUString(), 0, rPropertyValues);
81 }
82
83 // this is a member because our test classes have protected members :(
CheckRedlineFootnotesHidden()84 void SwLayoutWriter::CheckRedlineFootnotesHidden()
85 {
86 discardDumpedLayout();
87 xmlDocPtr pXmlDoc = parseLayoutDump();
88 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "24");
89 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType", "PortionType::Footnote");
90 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
91 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
92 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
93 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType", "PortionType::Footnote");
94 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
95 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex", "13");
96 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
97 "PortionType::FootnoteNum");
98 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
99 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "nType",
100 "PortionType::Text");
101 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "Portion", "ac");
102 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/merged", "paraPropsNodeIndex", "16");
103 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
104 "PortionType::FootnoteNum");
105 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
106 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
107 "PortionType::Text");
108 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "mo");
109 }
110
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineFootnotes)111 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFootnotes)
112 {
113 createDoc("redline_footnotes.odt");
114 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
115 CPPUNIT_ASSERT(pTextDoc);
116 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
117 SwRootFrame* pLayout(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
118 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
119
120 // verify after load
121 CheckRedlineFootnotesHidden();
122
123 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
124 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
125 discardDumpedLayout();
126 xmlDocPtr pXmlDoc = parseLayoutDump();
127
128 // show: nothing is merged
129 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
130 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
131 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
132 xmlXPathFreeObject(pXmlObj);
133 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType", "PortionType::Footnote");
134 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
135 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
136 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
137 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
138 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
139 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType", "PortionType::Footnote");
140 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
141
142 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
143 "PortionType::FootnoteNum");
144 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
145 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "nType",
146 "PortionType::Text");
147 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "Portion", "a");
148 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[2]", "nType",
149 "PortionType::Text");
150 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[2]", "Portion", "b");
151 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[3]", "nType",
152 "PortionType::Text");
153 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[3]", "Portion", "c");
154 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
155 "PortionType::FootnoteNum");
156 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
157 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
158 "PortionType::Text");
159 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "def");
160 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Text");
161 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "b");
162 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Special[1]", "nType", "PortionType::Footnote");
163 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Special[1]", "rText", "3");
164 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "nType", "PortionType::Text");
165 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "Portion", "ar");
166 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[3]/txt[1]/Special[1]", "nType",
167 "PortionType::FootnoteNum");
168 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[3]/txt[1]/Special[1]", "rText", "3");
169 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[3]/txt[1]/Text[1]", "nType",
170 "PortionType::Text");
171 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[3]/txt[1]/Text[1]", "Portion", "ghi");
172 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Special[1]", "nType", "PortionType::Footnote");
173 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Special[1]", "rText", "4");
174 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
175 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
176 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
177 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
178 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Special[2]", "nType", "PortionType::Footnote");
179 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Special[2]", "rText", "5");
180
181 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[4]/txt[1]/Special[1]", "nType",
182 "PortionType::FootnoteNum");
183 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[4]/txt[1]/Special[1]", "rText", "4");
184 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[4]/txt[1]/Text[1]", "nType",
185 "PortionType::Text");
186 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[4]/txt[1]/Text[1]", "Portion", "jkl");
187 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Special[1]", "nType",
188 "PortionType::FootnoteNum");
189 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Special[1]", "rText", "5");
190 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[1]", "nType",
191 "PortionType::Text");
192 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[1]", "Portion", "m");
193 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[2]", "nType",
194 "PortionType::Text");
195 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[2]", "Portion", "n");
196 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[3]", "nType",
197 "PortionType::Text");
198 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[3]", "Portion", "o");
199
200 // verify after hide
201 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
202 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
203 discardDumpedLayout();
204 CheckRedlineFootnotesHidden();
205 }
206
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineFlysInBody)207 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysInBody)
208 {
209 loadURL("private:factory/swriter", nullptr);
210 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
211 CPPUNIT_ASSERT(pTextDoc);
212 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
213 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
214 SwRootFrame* pLayout(pWrtShell->GetLayout());
215 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
216 pWrtShell->Insert("foo");
217 pWrtShell->SplitNode(false);
218 pWrtShell->Insert("bar");
219 pWrtShell->SplitNode(false);
220 pWrtShell->Insert("baz");
221 SfxItemSet flySet(pDoc->GetAttrPool(),
222 svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{});
223 SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
224 pWrtShell->StartOfSection(false);
225 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
226 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
227 flySet.Put(anchor);
228 SwFormatFrameSize size(ATT_MIN_SIZE, 1000, 1000);
229 flySet.Put(size); // set a size, else we get 1 char per line...
230 SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
231 CPPUNIT_ASSERT(pFly != nullptr);
232 // move inside fly
233 pWrtShell->GotoFly(pFly->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
234 pWrtShell->Insert("abc");
235 pWrtShell->SplitNode(false);
236 pWrtShell->Insert("def");
237 pWrtShell->SplitNode(false);
238 pWrtShell->Insert("ghi");
239
240 lcl_dispatchCommand(mxComponent, ".uno:TrackChanges", {});
241 // delete redline inside fly
242 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
243 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
244 pWrtShell->Delete();
245
246 pWrtShell->SttEndDoc(true); // note: SttDoc actually moves to start of fly?
247 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
248 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
249 pWrtShell->Delete();
250
251 for (int i = 0; i < 2; ++i)
252 {
253 if (i == 1) // secondly, try with different anchor type
254 {
255 anchor.SetType(RndStdIds::FLY_AT_PARA);
256 SwPosition pos(*anchor.GetContentAnchor());
257 pos.nContent.Assign(nullptr, 0);
258 anchor.SetAnchor(&pos);
259 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
260 }
261
262 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
263 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
264 discardDumpedLayout();
265 xmlDocPtr pXmlDoc = parseLayoutDump();
266 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
267 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
268 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
269 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
270 "paraPropsNodeIndex", "6");
271 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
272 "PortionType::Para");
273 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
274 "ahi");
275
276 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
277 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
278 discardDumpedLayout();
279 pXmlDoc = parseLayoutDump();
280
281 { // show: nothing is merged
282 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
283 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
284 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
285 xmlXPathFreeObject(pXmlObj);
286 }
287
288 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
289 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
290 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
291 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
292 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
293 "PortionType::Text");
294 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
295 "a");
296 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
297 "PortionType::Text");
298 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
299 "bc");
300 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
301 "PortionType::Para");
302 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
303 "def");
304 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
305 "PortionType::Text");
306 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
307 "g");
308 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
309 "PortionType::Text");
310 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
311 "hi");
312 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
313 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
314 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
315 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
316 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
317 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
318 }
319
320 // anchor to 2nd (deleted) paragraph
321 pWrtShell->StartOfSection();
322 pWrtShell->Down(false, 1);
323 anchor.SetType(RndStdIds::FLY_AT_CHAR);
324 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
325 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
326
327 for (int i = 0; i < 2; ++i)
328 {
329 if (i == 1) // secondly, try with different anchor type
330 {
331 anchor.SetType(RndStdIds::FLY_AT_PARA);
332 SwPosition pos(*anchor.GetContentAnchor());
333 pos.nContent.Assign(nullptr, 0);
334 anchor.SetAnchor(&pos);
335 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
336 }
337
338 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
339 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
340 discardDumpedLayout();
341 xmlDocPtr pXmlDoc = parseLayoutDump();
342 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
343 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
344 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
345
346 { // hide: no anchored object shown
347 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
348 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
349 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
350 xmlXPathFreeObject(pXmlObj);
351 }
352
353 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
354 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
355 discardDumpedLayout();
356 pXmlDoc = parseLayoutDump();
357
358 { // show: nothing is merged
359 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
360 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
361 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
362 xmlXPathFreeObject(pXmlObj);
363 }
364
365 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
366 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
367 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
368 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
369 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
370 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
371 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
372 "PortionType::Text");
373 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
374 "a");
375 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
376 "PortionType::Text");
377 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
378 "bc");
379 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
380 "PortionType::Para");
381 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
382 "def");
383 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
384 "PortionType::Text");
385 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
386 "g");
387 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
388 "PortionType::Text");
389 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
390 "hi");
391 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
392 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
393 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
394 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
395 }
396
397 // anchor to 3rd paragraph
398 pWrtShell->EndOfSection();
399 anchor.SetType(RndStdIds::FLY_AT_CHAR);
400 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
401 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
402
403 for (int i = 0; i < 2; ++i)
404 {
405 if (i == 1) // secondly, try with different anchor type
406 {
407 anchor.SetType(RndStdIds::FLY_AT_PARA);
408 SwPosition pos(*anchor.GetContentAnchor());
409 pos.nContent.Assign(nullptr, 0);
410 anchor.SetAnchor(&pos);
411 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
412 }
413
414 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
415 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
416 discardDumpedLayout();
417 xmlDocPtr pXmlDoc = parseLayoutDump();
418 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
419 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
420 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
421 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
422 "paraPropsNodeIndex", "6");
423 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
424 "PortionType::Para");
425 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
426 "ahi");
427
428 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
429 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
430 discardDumpedLayout();
431 pXmlDoc = parseLayoutDump();
432
433 { // show: nothing is merged
434 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
435 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
436 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
437 xmlXPathFreeObject(pXmlObj);
438 }
439
440 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
441 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
442 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
443 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
444 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
445 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
446 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
447 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
448 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
449 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
450 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
451 "PortionType::Text");
452 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
453 "a");
454 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
455 "PortionType::Text");
456 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
457 "bc");
458 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
459 "PortionType::Para");
460 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
461 "def");
462 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
463 "PortionType::Text");
464 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
465 "g");
466 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
467 "PortionType::Text");
468 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
469 "hi");
470 }
471 }
472
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,TestTdf134272)473 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, TestTdf134272)
474 {
475 SwDoc* pDoc = createDoc("tdf134472.odt");
476 CPPUNIT_ASSERT(pDoc);
477 xmlDocPtr pXmlDoc = parseLayoutDump();
478 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/infos/bounds", "height", "843");
479 }
480
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineFlysInHeader)481 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysInHeader)
482 {
483 loadURL("private:factory/swriter", nullptr);
484 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
485 CPPUNIT_ASSERT(pTextDoc);
486 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
487 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
488 SwRootFrame* pLayout(pWrtShell->GetLayout());
489 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
490 pWrtShell->ChangeHeaderOrFooter("Default Style", /*bHeader*/ true, /*bOn*/ true, false);
491 CPPUNIT_ASSERT(
492 pWrtShell
493 ->IsInHeaderFooter()); // assume this is supposed to put cursor in the new header...
494 pWrtShell->Insert("foo");
495 pWrtShell->SplitNode(false);
496 pWrtShell->Insert("bar");
497 pWrtShell->SplitNode(false);
498 pWrtShell->Insert("baz");
499 SfxItemSet flySet(pDoc->GetAttrPool(),
500 svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{});
501 SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
502 pWrtShell->StartOfSection(false);
503 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
504 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
505 flySet.Put(anchor);
506 SwFormatFrameSize size(ATT_MIN_SIZE, 1000, 1000);
507 flySet.Put(size); // set a size, else we get 1 char per line...
508 SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
509 CPPUNIT_ASSERT(pFly != nullptr);
510 // move inside fly
511 pWrtShell->GotoFly(pFly->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
512 pWrtShell->Insert("abc");
513 pWrtShell->SplitNode(false);
514 pWrtShell->Insert("def");
515 pWrtShell->SplitNode(false);
516 pWrtShell->Insert("ghi");
517
518 lcl_dispatchCommand(mxComponent, ".uno:TrackChanges", {});
519 // delete redline inside fly
520 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
521 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
522 pWrtShell->Delete();
523
524 pWrtShell->GotoHeaderText();
525 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
526 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
527 pWrtShell->Delete();
528
529 for (int i = 0; i < 2; ++i)
530 {
531 if (i == 1) // secondly, try with different anchor type
532 {
533 anchor.SetType(RndStdIds::FLY_AT_PARA);
534 SwPosition pos(*anchor.GetContentAnchor());
535 pos.nContent.Assign(nullptr, 0);
536 anchor.SetAnchor(&pos);
537 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
538 }
539
540 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
541 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
542 discardDumpedLayout();
543 xmlDocPtr pXmlDoc = parseLayoutDump();
544 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
545 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
546 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
547 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Para");
548 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
549 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/merged",
550 "paraPropsNodeIndex", "11");
551 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
552 "PortionType::Para");
553 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
554 "Portion", "ahi");
555
556 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
557 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
558 discardDumpedLayout();
559 pXmlDoc = parseLayoutDump();
560
561 { // show: nothing is merged
562 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
563 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
564 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
565 xmlXPathFreeObject(pXmlObj);
566 }
567
568 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
569 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
570 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Text");
571 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
572 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "nType", "PortionType::Text");
573 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
574 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
575 "PortionType::Text");
576 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
577 "Portion", "a");
578 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
579 "PortionType::Text");
580 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
581 "Portion", "bc");
582 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
583 "PortionType::Para");
584 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
585 "Portion", "def");
586 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
587 "PortionType::Text");
588 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
589 "Portion", "g");
590 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
591 "PortionType::Text");
592 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
593 "Portion", "hi");
594 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "nType", "PortionType::Para");
595 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
596 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "nType", "PortionType::Text");
597 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
598 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "nType", "PortionType::Text");
599 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
600 }
601
602 // anchor to 2nd (deleted) paragraph
603 pWrtShell->StartOfSection();
604 pWrtShell->Down(false, 1);
605 anchor.SetType(RndStdIds::FLY_AT_CHAR);
606 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
607 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
608
609 for (int i = 0; i < 2; ++i)
610 {
611 if (i == 1) // secondly, try with different anchor type
612 {
613 anchor.SetType(RndStdIds::FLY_AT_PARA);
614 SwPosition pos(*anchor.GetContentAnchor());
615 pos.nContent.Assign(nullptr, 0);
616 anchor.SetAnchor(&pos);
617 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
618 }
619
620 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
621 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
622 discardDumpedLayout();
623 xmlDocPtr pXmlDoc = parseLayoutDump();
624 // now the frame has no Text portion? not sure why it's a 0-length one first and now none?
625 // assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
626 // assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
627 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
628 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Para");
629 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
630
631 { // hide: no anchored object shown
632 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
633 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
634 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
635 xmlXPathFreeObject(pXmlObj);
636 }
637
638 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
639 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
640 discardDumpedLayout();
641 pXmlDoc = parseLayoutDump();
642
643 { // show: nothing is merged
644 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
645 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
646 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
647 xmlXPathFreeObject(pXmlObj);
648 }
649
650 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
651 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
652 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Text");
653 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
654 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "nType", "PortionType::Text");
655 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
656 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "nType", "PortionType::Para");
657 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
658 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
659 "PortionType::Text");
660 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
661 "Portion", "a");
662 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
663 "PortionType::Text");
664 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
665 "Portion", "bc");
666 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
667 "PortionType::Para");
668 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
669 "Portion", "def");
670 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
671 "PortionType::Text");
672 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
673 "Portion", "g");
674 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
675 "PortionType::Text");
676 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
677 "Portion", "hi");
678 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "nType", "PortionType::Text");
679 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
680 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "nType", "PortionType::Text");
681 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
682 }
683
684 // anchor to 3rd paragraph
685 pWrtShell->EndOfSection();
686 anchor.SetType(RndStdIds::FLY_AT_CHAR);
687 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
688 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
689
690 for (int i = 0; i < 2; ++i)
691 {
692 if (i == 1) // secondly, try with different anchor type
693 {
694 anchor.SetType(RndStdIds::FLY_AT_PARA);
695 SwPosition pos(*anchor.GetContentAnchor());
696 pos.nContent.Assign(nullptr, 0);
697 anchor.SetAnchor(&pos);
698 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
699 }
700
701 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
702 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
703 discardDumpedLayout();
704 xmlDocPtr pXmlDoc = parseLayoutDump();
705 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
706 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
707 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
708 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Para");
709 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
710 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/merged",
711 "paraPropsNodeIndex", "11");
712 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
713 "PortionType::Para");
714 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
715 "Portion", "ahi");
716
717 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
718 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
719 discardDumpedLayout();
720 pXmlDoc = parseLayoutDump();
721
722 { // show: nothing is merged
723 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
724 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
725 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
726 xmlXPathFreeObject(pXmlObj);
727 }
728
729 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
730 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
731 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Text");
732 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
733 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "nType", "PortionType::Text");
734 assertXPath(pXmlDoc, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
735 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "nType", "PortionType::Para");
736 assertXPath(pXmlDoc, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
737 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "nType", "PortionType::Text");
738 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
739 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "nType", "PortionType::Text");
740 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
741 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
742 "PortionType::Text");
743 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
744 "Portion", "a");
745 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
746 "PortionType::Text");
747 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
748 "Portion", "bc");
749 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
750 "PortionType::Para");
751 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
752 "Portion", "def");
753 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
754 "PortionType::Text");
755 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
756 "Portion", "g");
757 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
758 "PortionType::Text");
759 assertXPath(pXmlDoc, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
760 "Portion", "hi");
761 }
762 }
763
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineFlysInFootnote)764 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysInFootnote)
765 {
766 loadURL("private:factory/swriter", nullptr);
767 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
768 CPPUNIT_ASSERT(pTextDoc);
769 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
770 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
771 SwRootFrame* pLayout(pWrtShell->GetLayout());
772 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
773 pWrtShell->InsertFootnote("");
774 CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote());
775
776 SfxItemSet flySet(pDoc->GetAttrPool(),
777 svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{});
778 SwFormatFrameSize size(ATT_MIN_SIZE, 1000, 1000);
779 flySet.Put(size); // set a size, else we get 1 char per line...
780 SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
781 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
782 flySet.Put(anchor);
783 // first fly is in first footnote that will be deleted
784 /* SwFrameFormat const* pFly1 =*/pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
785 pWrtShell->Insert("quux");
786
787 pWrtShell->SttEndDoc(false);
788
789 pWrtShell->InsertFootnote("");
790 CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote());
791 pWrtShell->Insert("foo");
792 pWrtShell->SplitNode(false);
793 pWrtShell->Insert("bar");
794 pWrtShell->SplitNode(false);
795 pWrtShell->Insert("baz");
796
797 pWrtShell->StartOfSection(false);
798 CPPUNIT_ASSERT(pWrtShell->IsCursorInFootnote());
799 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
800 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
801 flySet.Put(anchor);
802 // second fly is in second footnote that is not deleted
803 SwFrameFormat const* pFly = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
804 CPPUNIT_ASSERT(pFly != nullptr);
805 // move inside fly
806 pWrtShell->GotoFly(pFly->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
807 pWrtShell->Insert("abc");
808 pWrtShell->SplitNode(false);
809 pWrtShell->Insert("def");
810 pWrtShell->SplitNode(false);
811 pWrtShell->Insert("ghi");
812
813 lcl_dispatchCommand(mxComponent, ".uno:TrackChanges", {});
814 // delete redline inside fly
815 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
816 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
817 pWrtShell->Delete();
818
819 // pWrtShell->GotoFlyAnchor(); // sigh... why, now we're in the body...
820 pWrtShell->SttEndDoc(false);
821 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
822 pWrtShell->GotoFootnoteText();
823 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
824 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
825 pWrtShell->Delete();
826 pWrtShell->EndSelect(); // ?
827 // delete first footnote
828 pWrtShell->SttEndDoc(true);
829 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
830 pWrtShell->Delete();
831
832 for (int i = 0; i < 2; ++i)
833 {
834 if (i == 1) // secondly, try with different anchor type
835 {
836 anchor.SetType(RndStdIds::FLY_AT_PARA);
837 SwPosition pos(*anchor.GetContentAnchor());
838 pos.nContent.Assign(nullptr, 0);
839 anchor.SetAnchor(&pos);
840 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
841 }
842
843 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
844 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
845 discardDumpedLayout();
846 xmlDocPtr pXmlDoc = parseLayoutDump();
847 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
848 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
849 "PortionType::Footnote");
850 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
851 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
852 "7");
853 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/merged",
854 "paraPropsNodeIndex", "17");
855 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
856 "nType", "PortionType::Para");
857 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
858 "Portion", "ahi");
859 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
860 "PortionType::FootnoteNum");
861 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
862
863 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
864 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
865 discardDumpedLayout();
866 pXmlDoc = parseLayoutDump();
867
868 { // show: nothing is merged
869 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
870 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
871 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
872 xmlXPathFreeObject(pXmlObj);
873 }
874
875 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
876 "PortionType::Footnote");
877 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
878 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType",
879 "PortionType::Footnote");
880 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
881 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
882 "nType", "PortionType::Para");
883 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
884 "Portion", "quux");
885 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
886 "PortionType::FootnoteNum");
887 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
888 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
889 "nType", "PortionType::Text");
890 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
891 "Portion", "a");
892 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
893 "nType", "PortionType::Text");
894 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
895 "Portion", "bc");
896 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
897 "nType", "PortionType::Para");
898 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
899 "Portion", "def");
900 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
901 "nType", "PortionType::Text");
902 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
903 "Portion", "g");
904 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
905 "nType", "PortionType::Text");
906 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
907 "Portion", "hi");
908 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
909 "PortionType::FootnoteNum");
910 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
911 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
912 "PortionType::Text");
913 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
914 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType",
915 "PortionType::Text");
916 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
917 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType",
918 "PortionType::Para");
919 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
920 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType",
921 "PortionType::Text");
922 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
923 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType",
924 "PortionType::Text");
925 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
926 }
927
928 // anchor to 2nd (deleted) paragraph
929 pWrtShell->SttEndDoc(false);
930 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
931 pWrtShell->GotoFootnoteText();
932 pWrtShell->Down(false, 1);
933 anchor.SetType(RndStdIds::FLY_AT_CHAR);
934 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
935 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
936
937 for (int i = 0; i < 2; ++i)
938 {
939 if (i == 1) // secondly, try with different anchor type
940 {
941 anchor.SetType(RndStdIds::FLY_AT_PARA);
942 SwPosition pos(*anchor.GetContentAnchor());
943 pos.nContent.Assign(nullptr, 0);
944 anchor.SetAnchor(&pos);
945 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
946 }
947
948 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
949 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
950 discardDumpedLayout();
951 xmlDocPtr pXmlDoc = parseLayoutDump();
952
953 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
954 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
955 "PortionType::Footnote");
956 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
957 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
958 "7");
959 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
960 "PortionType::FootnoteNum");
961 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
962
963 { // hide: no anchored object shown
964 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
965 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
966 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
967 xmlXPathFreeObject(pXmlObj);
968 }
969
970 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
971 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
972 discardDumpedLayout();
973 pXmlDoc = parseLayoutDump();
974
975 { // show: nothing is merged
976 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
977 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
978 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
979 xmlXPathFreeObject(pXmlObj);
980 }
981
982 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
983 "PortionType::Footnote");
984 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
985 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType",
986 "PortionType::Footnote");
987 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
988 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
989 "nType", "PortionType::Para");
990 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
991 "Portion", "quux");
992 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
993 "PortionType::FootnoteNum");
994 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
995 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
996 "PortionType::FootnoteNum");
997 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
998 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
999 "PortionType::Text");
1000 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
1001 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType",
1002 "PortionType::Text");
1003 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
1004 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
1005 "nType", "PortionType::Text");
1006 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
1007 "Portion", "a");
1008 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
1009 "nType", "PortionType::Text");
1010 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
1011 "Portion", "bc");
1012 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
1013 "nType", "PortionType::Para");
1014 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
1015 "Portion", "def");
1016 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
1017 "nType", "PortionType::Text");
1018 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
1019 "Portion", "g");
1020 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
1021 "nType", "PortionType::Text");
1022 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
1023 "Portion", "hi");
1024 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType",
1025 "PortionType::Para");
1026 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
1027 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType",
1028 "PortionType::Text");
1029 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
1030 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType",
1031 "PortionType::Text");
1032 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
1033 }
1034
1035 // anchor to 3rd paragraph
1036 pWrtShell->EndOfSection();
1037 pWrtShell->SttEndDoc(false);
1038 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1039 pWrtShell->GotoFootnoteText();
1040 pWrtShell->EndOfSection();
1041 anchor.SetType(RndStdIds::FLY_AT_CHAR);
1042 anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1043 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
1044
1045 for (int i = 0; i < 2; ++i)
1046 {
1047 if (i == 1) // secondly, try with different anchor type
1048 {
1049 anchor.SetType(RndStdIds::FLY_AT_PARA);
1050 SwPosition pos(*anchor.GetContentAnchor());
1051 pos.nContent.Assign(nullptr, 0);
1052 anchor.SetAnchor(&pos);
1053 pDoc->SetAttr(anchor, *const_cast<SwFrameFormat*>(pFly));
1054 }
1055
1056 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1057 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1058 discardDumpedLayout();
1059 xmlDocPtr pXmlDoc = parseLayoutDump();
1060 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
1061 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1062 "PortionType::Footnote");
1063 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1064 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
1065 "7");
1066 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/merged",
1067 "paraPropsNodeIndex", "17");
1068 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1069 "nType", "PortionType::Para");
1070 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1071 "Portion", "ahi");
1072 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1073 "PortionType::FootnoteNum");
1074 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1075
1076 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1077 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1078 discardDumpedLayout();
1079 pXmlDoc = parseLayoutDump();
1080
1081 { // show: nothing is merged
1082 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1083 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1084 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1085 xmlXPathFreeObject(pXmlObj);
1086 }
1087
1088 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1089 "PortionType::Footnote");
1090 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1091 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "nType",
1092 "PortionType::Footnote");
1093 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
1094 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1095 "nType", "PortionType::Para");
1096 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1097 "Portion", "quux");
1098 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1099 "PortionType::FootnoteNum");
1100 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1101 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
1102 "PortionType::FootnoteNum");
1103 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
1104 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
1105 "PortionType::Text");
1106 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
1107 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType",
1108 "PortionType::Text");
1109 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
1110 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType",
1111 "PortionType::Para");
1112 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
1113 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
1114 "nType", "PortionType::Text");
1115 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
1116 "Portion", "a");
1117 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
1118 "nType", "PortionType::Text");
1119 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
1120 "Portion", "bc");
1121 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
1122 "nType", "PortionType::Para");
1123 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
1124 "Portion", "def");
1125 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
1126 "nType", "PortionType::Text");
1127 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
1128 "Portion", "g");
1129 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
1130 "nType", "PortionType::Text");
1131 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
1132 "Portion", "hi");
1133 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType",
1134 "PortionType::Text");
1135 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
1136 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType",
1137 "PortionType::Text");
1138 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
1139 }
1140 }
1141
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf116486)1142 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf116486)
1143 {
1144 SwDoc* pDoc = createDoc("tdf116486.docx");
1145 CPPUNIT_ASSERT(pDoc);
1146 OUString aTop = parseDump("/root/page/body/txt/Special", "nHeight");
1147 CPPUNIT_ASSERT_EQUAL(OUString("4006"), aTop);
1148 }
1149
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf128198)1150 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf128198)
1151 {
1152 SwDoc* pDoc = createDoc("tdf128198-1.docx");
1153 CPPUNIT_ASSERT(pDoc);
1154 xmlDocPtr pLayout = parseLayoutDump();
1155 // the problem was that line 5 was truncated at "this "
1156 // due to the fly anchored in previous paragraph
1157 assertXPath(pLayout, "/root/page/body/txt[2]/LineBreak[5]", "Line",
1158 "to access any service, any time, anywhere. From this perspective, satellite "
1159 "boasts some ");
1160 assertXPath(pLayout, "/root/page/body/txt[2]/LineBreak[6]", "Line", "significant advantages. ");
1161 }
1162
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testNoLineBreakAtSlash)1163 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testNoLineBreakAtSlash)
1164 {
1165 load(DATA_DIRECTORY, "no-line-break-at-slash.fodt");
1166 xmlDocPtr pLayout = parseLayoutDump();
1167
1168 // the line break was between "Foostrasse 13/c/" and "2"
1169 xmlXPathObjectPtr pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[2]");
1170 CPPUNIT_ASSERT_EQUAL(std::string("Text"), std::string(reinterpret_cast<char const*>(
1171 pXmlObj->nodesetval->nodeTab[0]->name)));
1172 xmlXPathFreeObject(pXmlObj);
1173 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[3]");
1174 CPPUNIT_ASSERT_EQUAL(std::string("LineBreak"), std::string(reinterpret_cast<char const*>(
1175 pXmlObj->nodesetval->nodeTab[0]->name)));
1176 xmlXPathFreeObject(pXmlObj);
1177 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[4]");
1178 CPPUNIT_ASSERT_EQUAL(std::string("Text"), std::string(reinterpret_cast<char const*>(
1179 pXmlObj->nodesetval->nodeTab[0]->name)));
1180 xmlXPathFreeObject(pXmlObj);
1181 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[5]");
1182 CPPUNIT_ASSERT_EQUAL(std::string("Special"), std::string(reinterpret_cast<char const*>(
1183 pXmlObj->nodesetval->nodeTab[0]->name)));
1184 xmlXPathFreeObject(pXmlObj);
1185 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[6]");
1186 CPPUNIT_ASSERT_EQUAL(std::string("Text"), std::string(reinterpret_cast<char const*>(
1187 pXmlObj->nodesetval->nodeTab[0]->name)));
1188 xmlXPathFreeObject(pXmlObj);
1189 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[7]");
1190 CPPUNIT_ASSERT_EQUAL(std::string("LineBreak"), std::string(reinterpret_cast<char const*>(
1191 pXmlObj->nodesetval->nodeTab[0]->name)));
1192 xmlXPathFreeObject(pXmlObj);
1193 pXmlObj = getXPathNode(pLayout, "/root/page[1]/body/txt[1]/child::*[8]");
1194 CPPUNIT_ASSERT_EQUAL(std::string("Finish"), std::string(reinterpret_cast<char const*>(
1195 pXmlObj->nodesetval->nodeTab[0]->name)));
1196 xmlXPathFreeObject(pXmlObj);
1197
1198 assertXPath(pLayout, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "Blah blah bla bla bla ");
1199 assertXPath(pLayout, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "Foostrasse");
1200 assertXPath(pLayout, "/root/page[1]/body/txt[1]/Text[3]", "Portion", "13/c/2, etc.");
1201 }
1202
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineFlysInFlys)1203 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysInFlys)
1204 {
1205 loadURL("private:factory/swriter", nullptr);
1206 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1207 CPPUNIT_ASSERT(pTextDoc);
1208 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
1209 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
1210 SwRootFrame* pLayout(pWrtShell->GetLayout());
1211 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1212 pWrtShell->Insert("foo");
1213 pWrtShell->SplitNode(false);
1214 pWrtShell->Insert("bar");
1215 pWrtShell->SplitNode(false);
1216 pWrtShell->Insert("baz");
1217 SfxItemSet flySet(pDoc->GetAttrPool(),
1218 svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{});
1219 SwFormatFrameSize size(ATT_MIN_SIZE, 1000, 1000);
1220 flySet.Put(size); // set a size, else we get 1 char per line...
1221 pWrtShell->StartOfSection(false);
1222 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1223 SwFormatAnchor anchor1(RndStdIds::FLY_AT_CHAR);
1224 anchor1.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1225 flySet.Put(anchor1);
1226 SwFrameFormat const* pFly1 = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
1227 CPPUNIT_ASSERT(pFly1 != nullptr);
1228 // move inside fly1
1229 pWrtShell->GotoFly(pFly1->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1230 pWrtShell->Insert("abc");
1231 pWrtShell->SplitNode(false);
1232 pWrtShell->Insert("def");
1233 pWrtShell->SplitNode(false);
1234 pWrtShell->Insert("ghi");
1235
1236 SwFormatAnchor anchor2(RndStdIds::FLY_AT_CHAR);
1237 pWrtShell->StartOfSection(false); // start of fly...
1238 anchor2.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1239 flySet.Put(anchor2);
1240 SwFrameFormat const* pFly2 = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
1241 CPPUNIT_ASSERT(pFly2 != nullptr);
1242 // move inside fly2
1243 pWrtShell->GotoFly(pFly2->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1244 pWrtShell->Insert("jkl");
1245 pWrtShell->SplitNode(false);
1246 pWrtShell->Insert("mno");
1247 pWrtShell->SplitNode(false);
1248 pWrtShell->Insert("pqr");
1249
1250 lcl_dispatchCommand(mxComponent, ".uno:TrackChanges", {});
1251 // delete redline inside fly2
1252 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1253 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
1254 pWrtShell->Delete();
1255
1256 // delete redline inside fly1
1257 pWrtShell->GotoFly(pFly1->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1258 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1259 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
1260 pWrtShell->Delete();
1261
1262 pWrtShell->ClearMark(); // otherwise it refuses to leave the fly...
1263 pWrtShell->SttEndDoc(true); // note: SttDoc actually moves to start of fly?
1264 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1265 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
1266 pWrtShell->Delete();
1267
1268 for (int i = 0; i < 2; ++i)
1269 {
1270 if (i == 1) // secondly, try with different anchor type
1271 {
1272 anchor1.SetType(RndStdIds::FLY_AT_PARA);
1273 SwPosition pos(*anchor1.GetContentAnchor());
1274 pos.nContent.Assign(nullptr, 0);
1275 anchor1.SetAnchor(&pos);
1276 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1277 anchor2.SetType(RndStdIds::FLY_AT_PARA);
1278 pos.nNode = anchor2.GetContentAnchor()->nNode;
1279 anchor2.SetAnchor(&pos);
1280 pDoc->SetAttr(anchor2, *const_cast<SwFrameFormat*>(pFly2));
1281 }
1282
1283 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1284 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1285 discardDumpedLayout();
1286 xmlDocPtr pXmlDoc = parseLayoutDump();
1287 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1288 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
1289 "paraPropsNodeIndex", "6");
1290 assertXPath(
1291 pXmlDoc,
1292 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/merged",
1293 "paraPropsNodeIndex", "11");
1294 assertXPath(
1295 pXmlDoc,
1296 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1297 "nType", "PortionType::Para");
1298 assertXPath(
1299 pXmlDoc,
1300 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1301 "Portion", "jqr");
1302 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1303 "PortionType::Fly"); // remove???
1304 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1305 "PortionType::Lay");
1306 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1307 "abhi");
1308 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1309 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1310
1311 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1312 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1313 discardDumpedLayout();
1314 pXmlDoc = parseLayoutDump();
1315
1316 { // show: nothing is merged
1317 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1318 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1319 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1320 xmlXPathFreeObject(pXmlObj);
1321 }
1322
1323 assertXPath(
1324 pXmlDoc,
1325 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1326 "nType", "PortionType::Text");
1327 assertXPath(
1328 pXmlDoc,
1329 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1330 "Portion", "j");
1331 assertXPath(
1332 pXmlDoc,
1333 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
1334 "nType", "PortionType::Text");
1335 assertXPath(
1336 pXmlDoc,
1337 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
1338 "Portion", "kl");
1339 assertXPath(
1340 pXmlDoc,
1341 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
1342 "nType", "PortionType::Para");
1343 assertXPath(
1344 pXmlDoc,
1345 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
1346 "Portion", "mno");
1347 assertXPath(
1348 pXmlDoc,
1349 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
1350 "nType", "PortionType::Text");
1351 assertXPath(
1352 pXmlDoc,
1353 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
1354 "Portion", "p");
1355 assertXPath(
1356 pXmlDoc,
1357 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
1358 "nType", "PortionType::Text");
1359 assertXPath(
1360 pXmlDoc,
1361 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
1362 "Portion", "qr");
1363 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1364 "PortionType::Fly"); // remove???
1365 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1366 "PortionType::Text");
1367 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1368 "ab");
1369 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1370 "PortionType::Text");
1371 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1372 "c");
1373 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1374 "PortionType::Para");
1375 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1376 "def");
1377 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1378 "PortionType::Text");
1379 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1380 "g");
1381 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1382 "PortionType::Text");
1383 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1384 "hi");
1385 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1386 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1387 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1388 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1389 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1390 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1391 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1392 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1393 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1394 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1395 }
1396
1397 // anchor to 2nd (deleted) paragraph
1398 // also, switch the in-fly anchoring to the other fly, for additional fun!
1399 pWrtShell->StartOfSection();
1400 pWrtShell->Down(false, 1);
1401 anchor2.SetType(RndStdIds::FLY_AT_CHAR);
1402 anchor2.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1403 pDoc->SetAttr(anchor2, *const_cast<SwFrameFormat*>(pFly2));
1404 pWrtShell->GotoFly(pFly2->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1405 pWrtShell->Down(false, 1);
1406 anchor1.SetType(RndStdIds::FLY_AT_CHAR);
1407 anchor1.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1408 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1409
1410 for (int i = 0; i < 2; ++i)
1411 {
1412 if (i == 1) // secondly, try with different anchor type
1413 {
1414 anchor1.SetType(RndStdIds::FLY_AT_PARA);
1415 SwPosition pos(*anchor1.GetContentAnchor());
1416 pos.nContent.Assign(nullptr, 0);
1417 anchor1.SetAnchor(&pos);
1418 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1419 anchor2.SetType(RndStdIds::FLY_AT_PARA);
1420 pos.nNode = anchor2.GetContentAnchor()->nNode;
1421 anchor2.SetAnchor(&pos);
1422 pDoc->SetAttr(anchor2, *const_cast<SwFrameFormat*>(pFly2));
1423 }
1424
1425 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1426 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1427 discardDumpedLayout();
1428 xmlDocPtr pXmlDoc = parseLayoutDump();
1429 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1430 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1431 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1432
1433 { // hide: no anchored object shown
1434 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
1435 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1436 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1437 xmlXPathFreeObject(pXmlObj);
1438 }
1439
1440 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1441 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1442 discardDumpedLayout();
1443 pXmlDoc = parseLayoutDump();
1444
1445 { // show: nothing is merged
1446 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1447 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1448 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1449 xmlXPathFreeObject(pXmlObj);
1450 }
1451
1452 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1453 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1454 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1455 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1456 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1457 "PortionType::Text");
1458 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1459 "j");
1460 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1461 "PortionType::Text");
1462 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1463 "kl");
1464 assertXPath(
1465 pXmlDoc,
1466 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[1]",
1467 "nType", "PortionType::Text");
1468 assertXPath(
1469 pXmlDoc,
1470 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[1]",
1471 "Portion", "ab");
1472 assertXPath(
1473 pXmlDoc,
1474 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[2]",
1475 "nType", "PortionType::Text");
1476 assertXPath(
1477 pXmlDoc,
1478 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[2]",
1479 "Portion", "c");
1480 assertXPath(
1481 pXmlDoc,
1482 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[2]/Text[1]",
1483 "nType", "PortionType::Para");
1484 assertXPath(
1485 pXmlDoc,
1486 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[2]/Text[1]",
1487 "Portion", "def");
1488 assertXPath(
1489 pXmlDoc,
1490 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[1]",
1491 "nType", "PortionType::Text");
1492 assertXPath(
1493 pXmlDoc,
1494 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[1]",
1495 "Portion", "g");
1496 assertXPath(
1497 pXmlDoc,
1498 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[2]",
1499 "nType", "PortionType::Text");
1500 assertXPath(
1501 pXmlDoc,
1502 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[2]",
1503 "Portion", "hi");
1504 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Special[1]", "nType",
1505 "PortionType::Fly"); // remove???
1506 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1507 "PortionType::Lay");
1508 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1509 "mno");
1510 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1511 "PortionType::Text");
1512 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1513 "p");
1514 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1515 "PortionType::Text");
1516 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1517 "qr");
1518 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1519 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1520 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1521 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1522 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1523 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1524 }
1525
1526 // anchor to 3rd paragraph
1527 pWrtShell->SttEndDoc(false);
1528 anchor1.SetType(RndStdIds::FLY_AT_CHAR);
1529 anchor1.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1530 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1531 pWrtShell->GotoFly(pFly1->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1532 pWrtShell->EndOfSection();
1533 anchor2.SetType(RndStdIds::FLY_AT_CHAR);
1534 anchor2.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1535 pDoc->SetAttr(anchor2, *const_cast<SwFrameFormat*>(pFly2));
1536
1537 for (int i = 0; i < 2; ++i)
1538 {
1539 if (i == 1) // secondly, try with different anchor type
1540 {
1541 anchor1.SetType(RndStdIds::FLY_AT_PARA);
1542 SwPosition pos(*anchor1.GetContentAnchor());
1543 pos.nContent.Assign(nullptr, 0);
1544 anchor1.SetAnchor(&pos);
1545 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1546 anchor2.SetType(RndStdIds::FLY_AT_PARA);
1547 pos.nNode = anchor2.GetContentAnchor()->nNode;
1548 anchor2.SetAnchor(&pos);
1549 pDoc->SetAttr(anchor2, *const_cast<SwFrameFormat*>(pFly2));
1550 }
1551
1552 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1553 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1554 discardDumpedLayout();
1555 xmlDocPtr pXmlDoc = parseLayoutDump();
1556 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1557 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
1558 "paraPropsNodeIndex", "6");
1559 assertXPath(
1560 pXmlDoc,
1561 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/merged",
1562 "paraPropsNodeIndex", "11");
1563 assertXPath(
1564 pXmlDoc,
1565 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1566 "nType", "PortionType::Para");
1567 assertXPath(
1568 pXmlDoc,
1569 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1570 "Portion", "jqr");
1571 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1572 "PortionType::Fly"); // remove???
1573 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1574 "PortionType::Lay");
1575 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1576 "abhi");
1577 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1578 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1579
1580 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1581 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1582 discardDumpedLayout();
1583 pXmlDoc = parseLayoutDump();
1584
1585 { // show: nothing is merged
1586 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1587 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1588 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1589 xmlXPathFreeObject(pXmlObj);
1590 }
1591
1592 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1593 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1594 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1595 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1596 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1597 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1598 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1599 "PortionType::Text");
1600 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1601 "ab");
1602 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1603 "PortionType::Text");
1604 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1605 "c");
1606 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1607 "PortionType::Para");
1608 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1609 "def");
1610 assertXPath(
1611 pXmlDoc,
1612 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[1]",
1613 "nType", "PortionType::Text");
1614 assertXPath(
1615 pXmlDoc,
1616 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[1]",
1617 "Portion", "j");
1618 assertXPath(
1619 pXmlDoc,
1620 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[2]",
1621 "nType", "PortionType::Text");
1622 assertXPath(
1623 pXmlDoc,
1624 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[2]",
1625 "Portion", "kl");
1626 assertXPath(
1627 pXmlDoc,
1628 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[2]/Text[1]",
1629 "nType", "PortionType::Para");
1630 assertXPath(
1631 pXmlDoc,
1632 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[2]/Text[1]",
1633 "Portion", "mno");
1634 assertXPath(
1635 pXmlDoc,
1636 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[1]",
1637 "nType", "PortionType::Text");
1638 assertXPath(
1639 pXmlDoc,
1640 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[1]",
1641 "Portion", "p");
1642 assertXPath(
1643 pXmlDoc,
1644 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[2]",
1645 "nType", "PortionType::Text");
1646 assertXPath(
1647 pXmlDoc,
1648 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[2]",
1649 "Portion", "qr");
1650 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1651 "PortionType::Text");
1652 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Special[1]", "nType",
1653 "PortionType::Fly"); // remove???
1654 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1655 "g");
1656 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1657 "PortionType::Text");
1658 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1659 "hi");
1660 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1661 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1662 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1663 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1664 }
1665 }
1666
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineFlysAtFlys)1667 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineFlysAtFlys)
1668 {
1669 loadURL("private:factory/swriter", nullptr);
1670 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1671 CPPUNIT_ASSERT(pTextDoc);
1672 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
1673 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
1674 SwRootFrame* pLayout(pWrtShell->GetLayout());
1675 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1676 pWrtShell->Insert("foo");
1677 pWrtShell->SplitNode(false);
1678 pWrtShell->Insert("bar");
1679 pWrtShell->SplitNode(false);
1680 pWrtShell->Insert("baz");
1681 SfxItemSet flySet(pDoc->GetAttrPool(),
1682 svl::Items<RES_FRM_SIZE, RES_FRM_SIZE, RES_ANCHOR, RES_ANCHOR>{});
1683 SwFormatFrameSize size(ATT_MIN_SIZE, 1000, 1000);
1684 flySet.Put(size); // set a size, else we get 1 char per line...
1685 pWrtShell->StartOfSection(false);
1686 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1687 SwFormatAnchor anchor1(RndStdIds::FLY_AT_CHAR);
1688 anchor1.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1689 flySet.Put(anchor1);
1690 SwFrameFormat const* pFly1 = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
1691 CPPUNIT_ASSERT(pFly1 != nullptr);
1692 // move inside fly1
1693 pWrtShell->GotoFly(pFly1->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1694 pWrtShell->Insert("abc");
1695 pWrtShell->SplitNode(false);
1696 pWrtShell->Insert("def");
1697 pWrtShell->SplitNode(false);
1698 pWrtShell->Insert("ghi");
1699
1700 SwFormatAnchor anchor2(RndStdIds::FLY_AT_FLY);
1701 SwPosition pos(*pFly1->GetContent().GetContentIdx());
1702 anchor2.SetAnchor(&pos);
1703 flySet.Put(anchor2);
1704 SwFrameFormat const* pFly2 = pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true);
1705 CPPUNIT_ASSERT(pFly2 != nullptr);
1706 // move inside fly2
1707 pWrtShell->GotoFly(pFly2->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1708 pWrtShell->Insert("jkl");
1709 pWrtShell->SplitNode(false);
1710 pWrtShell->Insert("mno");
1711 pWrtShell->SplitNode(false);
1712 pWrtShell->Insert("pqr");
1713
1714 lcl_dispatchCommand(mxComponent, ".uno:TrackChanges", {});
1715 // delete redline inside fly2
1716 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1717 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/true, 8, /*bBasicCall=*/false);
1718 pWrtShell->Delete();
1719
1720 // delete redline inside fly1
1721 pWrtShell->GotoFly(pFly1->GetName(), FLYCNTTYPE_FRM, /*bSelFrame=*/false);
1722 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1723 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
1724 pWrtShell->Delete();
1725
1726 pWrtShell->ClearMark(); // otherwise it refuses to leave the fly...
1727 pWrtShell->SttEndDoc(true); // note: SttDoc actually moves to start of fly?
1728 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1729 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 7, /*bBasicCall=*/false);
1730 pWrtShell->Delete();
1731
1732 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1733 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1734 discardDumpedLayout();
1735 xmlDocPtr pXmlDoc = parseLayoutDump();
1736 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1737 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
1738 "paraPropsNodeIndex", "6");
1739 assertXPath(pXmlDoc,
1740 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/merged",
1741 "paraPropsNodeIndex", "11");
1742 assertXPath(pXmlDoc,
1743 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1744 "nType", "PortionType::Para");
1745 assertXPath(pXmlDoc,
1746 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1747 "Portion", "jqr");
1748 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1749 "PortionType::Fly"); // remove???
1750 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1751 "PortionType::Lay");
1752 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1753 "abhi");
1754 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1755 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1756
1757 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1758 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1759 discardDumpedLayout();
1760 pXmlDoc = parseLayoutDump();
1761
1762 { // show: nothing is merged
1763 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1764 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1765 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1766 xmlXPathFreeObject(pXmlObj);
1767 }
1768
1769 assertXPath(pXmlDoc,
1770 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1771 "nType", "PortionType::Text");
1772 assertXPath(pXmlDoc,
1773 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1774 "Portion", "j");
1775 assertXPath(pXmlDoc,
1776 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
1777 "nType", "PortionType::Text");
1778 assertXPath(pXmlDoc,
1779 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
1780 "Portion", "kl");
1781 assertXPath(pXmlDoc,
1782 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
1783 "nType", "PortionType::Para");
1784 assertXPath(pXmlDoc,
1785 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
1786 "Portion", "mno");
1787 assertXPath(pXmlDoc,
1788 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
1789 "nType", "PortionType::Text");
1790 assertXPath(pXmlDoc,
1791 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
1792 "Portion", "p");
1793 assertXPath(pXmlDoc,
1794 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
1795 "nType", "PortionType::Text");
1796 assertXPath(pXmlDoc,
1797 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
1798 "Portion", "qr");
1799 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1800 "PortionType::Fly"); // remove???
1801 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1802 "PortionType::Text");
1803 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1804 "ab");
1805 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1806 "PortionType::Text");
1807 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1808 "c");
1809 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1810 "PortionType::Para");
1811 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1812 "def");
1813 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1814 "PortionType::Text");
1815 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1816 "g");
1817 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1818 "PortionType::Text");
1819 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1820 "hi");
1821 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1822 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1823 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1824 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1825 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1826 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1827 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1828 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1829 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1830 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1831
1832 // anchor to 2nd (deleted) paragraph
1833 pWrtShell->StartOfSection();
1834 pWrtShell->Down(false, 1);
1835 anchor1.SetType(RndStdIds::FLY_AT_CHAR);
1836 anchor1.SetAnchor(pWrtShell->GetCursor()->GetPoint());
1837 pDoc->SetAttr(anchor1, *const_cast<SwFrameFormat*>(pFly1));
1838
1839 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1840 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1841 discardDumpedLayout();
1842 pXmlDoc = parseLayoutDump();
1843 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1844 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1845 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1846
1847 { // hide: no anchored object shown
1848 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//anchored");
1849 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1850 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1851 xmlXPathFreeObject(pXmlObj);
1852 }
1853
1854 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1855 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1856 discardDumpedLayout();
1857 pXmlDoc = parseLayoutDump();
1858
1859 { // show: nothing is merged
1860 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1861 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1862 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1863 xmlXPathFreeObject(pXmlObj);
1864 }
1865
1866 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1867 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1868 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1869 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1870 assertXPath(pXmlDoc,
1871 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1872 "nType", "PortionType::Text");
1873 assertXPath(pXmlDoc,
1874 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1875 "Portion", "j");
1876 assertXPath(pXmlDoc,
1877 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
1878 "nType", "PortionType::Text");
1879 assertXPath(pXmlDoc,
1880 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
1881 "Portion", "kl");
1882 assertXPath(pXmlDoc,
1883 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
1884 "nType", "PortionType::Para");
1885 assertXPath(pXmlDoc,
1886 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
1887 "Portion", "mno");
1888 assertXPath(pXmlDoc,
1889 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
1890 "nType", "PortionType::Text");
1891 assertXPath(pXmlDoc,
1892 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
1893 "Portion", "p");
1894 assertXPath(pXmlDoc,
1895 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
1896 "nType", "PortionType::Text");
1897 assertXPath(pXmlDoc,
1898 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
1899 "Portion", "qr");
1900 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1901 "PortionType::Text");
1902 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1903 "PortionType::Fly"); // remove???
1904 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1905 "ab");
1906 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1907 "PortionType::Text");
1908 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1909 "c");
1910 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1911 "PortionType::Para");
1912 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1913 "def");
1914 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1915 "PortionType::Text");
1916 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1917 "g");
1918 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1919 "PortionType::Text");
1920 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1921 "hi");
1922 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1923 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1924 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1925 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1926 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1927 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1928 }
1929
CheckRedlineSectionsHidden()1930 void SwLayoutWriter::CheckRedlineSectionsHidden()
1931 {
1932 discardDumpedLayout();
1933 xmlDocPtr pXmlDoc = parseLayoutDump();
1934 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "12");
1935 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1936 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "folah");
1937 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/merged", "paraPropsNodeIndex", "20");
1938 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "nType",
1939 "PortionType::Para");
1940 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "Portion", "folah");
1941 }
1942
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineSections)1943 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineSections)
1944 {
1945 createDoc("redline_sections.fodt");
1946 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1947 CPPUNIT_ASSERT(pTextDoc);
1948 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
1949 SwRootFrame* pLayout(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
1950 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
1951
1952 // verify after load
1953 CheckRedlineSectionsHidden();
1954
1955 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
1956 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
1957 // why is this needed explicitly?
1958 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
1959 discardDumpedLayout();
1960 xmlDocPtr pXmlDoc = parseLayoutDump();
1961
1962 // show: nothing is merged
1963 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
1964 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1965 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
1966 xmlXPathFreeObject(pXmlObj);
1967 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1968 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1969 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1970 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1971
1972 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1973 "nType", "PortionType::Para");
1974 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1975 "Portion", "FRAME");
1976 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "nType",
1977 "PortionType::Para");
1978 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "Portion", "bar");
1979 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[2]/Text[1]", "nType",
1980 "PortionType::Para");
1981 assertXPath(pXmlDoc, "/root/page[1]/body/section[1]/txt[2]/Text[1]", "Portion", "baz");
1982 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Text");
1983 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "b");
1984 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "nType", "PortionType::Text");
1985 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "Portion", "lah");
1986 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/Text[1]", "nType",
1987 "PortionType::Text");
1988 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/Text[1]", "Portion", "fo");
1989 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/Text[2]", "nType",
1990 "PortionType::Text");
1991 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[1]/Text[2]", "Portion", "o");
1992 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[2]/Text[1]", "nType",
1993 "PortionType::Para");
1994 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[2]/Text[1]", "Portion", "bar");
1995 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/Text[1]", "nType",
1996 "PortionType::Text");
1997 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/Text[1]", "Portion", "b");
1998 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/Text[2]", "nType",
1999 "PortionType::Text");
2000 assertXPath(pXmlDoc, "/root/page[1]/body/section[2]/txt[3]/Text[2]", "Portion", "lah");
2001
2002 // verify after hide
2003 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2004 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2005 // why is this needed explicitly?
2006 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2007 discardDumpedLayout();
2008 CheckRedlineSectionsHidden();
2009 }
2010
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineTables)2011 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineTables)
2012 {
2013 createDoc("redline_table.fodt");
2014 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2015 CPPUNIT_ASSERT(pTextDoc);
2016 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
2017 SwRootFrame* pLayout(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
2018 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2019
2020 // verify after load
2021 discardDumpedLayout();
2022 xmlDocPtr pXmlDoc = parseLayoutDump();
2023 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "12");
2024 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2025 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foar");
2026
2027 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2028 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
2029 // why is this needed explicitly?
2030 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2031 discardDumpedLayout();
2032 pXmlDoc = parseLayoutDump();
2033
2034 // show: nothing is merged
2035 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
2036 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
2037 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
2038 xmlXPathFreeObject(pXmlObj);
2039 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
2040 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
2041 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
2042 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
2043
2044 assertXPath(pXmlDoc,
2045 "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
2046 "nType", "PortionType::Para");
2047 assertXPath(pXmlDoc,
2048 "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
2049 "Portion", "FRAME");
2050 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/Text[1]", "nType",
2051 "PortionType::Para");
2052 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/Text[1]", "Portion",
2053 "aaa");
2054 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[2]/cell[2]/txt[1]/Text[1]", "nType",
2055 "PortionType::Para");
2056 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[2]/cell[2]/txt[1]/Text[1]", "Portion",
2057 "ddd");
2058 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Text");
2059 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "b");
2060 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "nType", "PortionType::Text");
2061 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "Portion", "ar");
2062
2063 // verify after hide
2064 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2065 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2066 // why is this needed explicitly?
2067 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2068 discardDumpedLayout();
2069 pXmlDoc = parseLayoutDump();
2070 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "12");
2071 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2072 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foar");
2073 }
2074
2075 // this mainly tests that splitting portions across redlines in SwAttrIter works
CheckRedlineCharAttributesHidden()2076 void SwLayoutWriter::CheckRedlineCharAttributesHidden()
2077 {
2078 discardDumpedLayout();
2079 xmlDocPtr pXmlDoc = parseLayoutDump();
2080 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "9");
2081 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2082 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foobaz");
2083 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/merged", "paraPropsNodeIndex", "10");
2084 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
2085 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "foobaz");
2086 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/merged", "paraPropsNodeIndex", "11");
2087 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
2088 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "foo");
2089 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
2090 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "baz");
2091 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/merged", "paraPropsNodeIndex", "12");
2092 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/Text[1]", "nType", "PortionType::Text");
2093 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/Text[1]", "Portion", "foo");
2094 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/Text[2]", "nType", "PortionType::Text");
2095 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/Text[2]", "Portion", "baz");
2096 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/merged", "paraPropsNodeIndex", "13");
2097 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/Text[1]", "nType", "PortionType::Text");
2098 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/Text[1]", "Portion", "foo");
2099 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/Text[2]", "nType", "PortionType::Text");
2100 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/Text[2]", "Portion", "baz");
2101 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/merged", "paraPropsNodeIndex", "14");
2102 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/Text[1]", "nType", "PortionType::Text");
2103 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/Text[1]", "Portion", "foo");
2104 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/Text[2]", "nType", "PortionType::Text");
2105 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/Text[2]", "Portion", "baz");
2106 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/merged", "paraPropsNodeIndex", "15");
2107 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/Text[1]", "nType", "PortionType::Text");
2108 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/Text[1]", "Portion", "foo");
2109 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/Text[2]", "nType", "PortionType::Text");
2110 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/Text[2]", "Portion", "baz");
2111 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/merged", "paraPropsNodeIndex", "16");
2112 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[1]", "nType", "PortionType::Text");
2113 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[1]", "Portion", "foo");
2114 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[2]", "nType", "PortionType::Text");
2115 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[2]", "Portion", "baz");
2116 assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/merged", "paraPropsNodeIndex", "17");
2117 assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/Text[1]", "nType", "PortionType::Para");
2118 assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/Text[1]", "Portion", "foobaz");
2119 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/merged", "paraPropsNodeIndex", "18");
2120 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[1]", "nType", "PortionType::Text");
2121 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[1]", "Portion", "fo");
2122 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[2]", "nType", "PortionType::Text");
2123 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[2]", "Portion", "ob");
2124 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[3]", "nType", "PortionType::Text");
2125 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[3]", "Portion", "az");
2126 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/merged", "paraPropsNodeIndex", "19");
2127 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[1]", "nType", "PortionType::Para");
2128 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[1]", "Portion", "foobaz");
2129 }
2130
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineCharAttributes)2131 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineCharAttributes)
2132 {
2133 createDoc("redline_charatr.fodt");
2134 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2135 CPPUNIT_ASSERT(pTextDoc);
2136 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
2137 SwRootFrame* pLayout(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
2138 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2139
2140 // verify after load
2141 CheckRedlineCharAttributesHidden();
2142
2143 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2144 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
2145 // why is this needed explicitly?
2146 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2147 discardDumpedLayout();
2148 xmlDocPtr pXmlDoc = parseLayoutDump();
2149
2150 // show: nothing is merged
2151 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//merged");
2152 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
2153 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
2154 xmlXPathFreeObject(pXmlObj);
2155 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
2156 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foo");
2157 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
2158 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "bar");
2159 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[3]", "nType", "PortionType::Text");
2160 assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[3]", "Portion", "baz");
2161 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Text");
2162 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "foo");
2163 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "nType", "PortionType::Text");
2164 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[2]", "Portion", "bar");
2165 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[3]", "nType", "PortionType::Text");
2166 assertXPath(pXmlDoc, "/root/page[1]/body/txt[2]/Text[3]", "Portion", "baz");
2167 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
2168 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "foo");
2169 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
2170 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "bar");
2171 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[3]", "nType", "PortionType::Text");
2172 assertXPath(pXmlDoc, "/root/page[1]/body/txt[3]/Text[3]", "Portion", "baz");
2173 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/Text[1]", "nType", "PortionType::Text");
2174 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/Text[1]", "Portion", "foo");
2175 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/Text[2]", "nType", "PortionType::Text");
2176 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/Text[2]", "Portion", "bar");
2177 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/Text[3]", "nType", "PortionType::Text");
2178 assertXPath(pXmlDoc, "/root/page[1]/body/txt[4]/Text[3]", "Portion", "baz");
2179 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/Text[1]", "nType", "PortionType::Text");
2180 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/Text[1]", "Portion", "foo");
2181 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/Text[2]", "nType", "PortionType::Text");
2182 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/Text[2]", "Portion", "bar");
2183 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/Text[3]", "nType", "PortionType::Text");
2184 assertXPath(pXmlDoc, "/root/page[1]/body/txt[5]/Text[3]", "Portion", "baz");
2185 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/Text[1]", "nType", "PortionType::Text");
2186 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/Text[1]", "Portion", "foo");
2187 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/Text[2]", "nType", "PortionType::Text");
2188 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/Text[2]", "Portion", "bar");
2189 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/Text[3]", "nType", "PortionType::Text");
2190 assertXPath(pXmlDoc, "/root/page[1]/body/txt[6]/Text[3]", "Portion", "baz");
2191 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/Text[1]", "nType", "PortionType::Text");
2192 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/Text[1]", "Portion", "foo");
2193 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/Text[2]", "nType", "PortionType::Text");
2194 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/Text[2]", "Portion", "bar");
2195 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/Text[3]", "nType", "PortionType::Text");
2196 assertXPath(pXmlDoc, "/root/page[1]/body/txt[7]/Text[3]", "Portion", "baz");
2197 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[1]", "nType", "PortionType::Text");
2198 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[1]", "Portion", "foo");
2199 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[2]", "nType", "PortionType::Text");
2200 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[2]", "Portion", "ba");
2201 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[3]", "nType", "PortionType::Text");
2202 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[3]", "Portion", "r");
2203 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[4]", "nType", "PortionType::Text");
2204 assertXPath(pXmlDoc, "/root/page[1]/body/txt[8]/Text[4]", "Portion", "baz");
2205 assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/Text[1]", "nType", "PortionType::Text");
2206 assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/Text[1]", "Portion", "foo");
2207 assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/Text[2]", "nType", "PortionType::Text");
2208 assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/Text[2]", "Portion", "bar");
2209 assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/Text[3]", "nType", "PortionType::Text");
2210 assertXPath(pXmlDoc, "/root/page[1]/body/txt[9]/Text[3]", "Portion", "baz");
2211 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[1]", "nType", "PortionType::Text");
2212 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[1]", "Portion", "fo");
2213 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[2]", "nType", "PortionType::Text");
2214 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[2]", "Portion", "o");
2215 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[3]", "nType", "PortionType::Text");
2216 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[3]", "Portion", "bar");
2217 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[4]", "nType", "PortionType::Text");
2218 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[4]", "Portion", "b");
2219 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[5]", "nType", "PortionType::Text");
2220 assertXPath(pXmlDoc, "/root/page[1]/body/txt[10]/Text[5]", "Portion", "az");
2221 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[1]", "nType", "PortionType::Text");
2222 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[1]", "Portion", "foo");
2223 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[2]", "nType", "PortionType::Text");
2224 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[2]", "Portion", "b");
2225 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[3]", "nType", "PortionType::Text");
2226 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[3]", "Portion", "a");
2227 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[4]", "nType", "PortionType::Text");
2228 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[4]", "Portion", "r");
2229 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[5]", "nType", "PortionType::Text");
2230 assertXPath(pXmlDoc, "/root/page[1]/body/txt[11]/Text[5]", "Portion", "baz");
2231
2232 // verify after hide
2233 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2234 CPPUNIT_ASSERT(pLayout->IsHideRedlines());
2235 // why is this needed explicitly?
2236 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2237 CheckRedlineCharAttributesHidden();
2238 }
2239
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineShowHideFootnotePagination)2240 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineShowHideFootnotePagination)
2241 {
2242 createDoc("redline_footnote_pagination.fodt");
2243 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2244 CPPUNIT_ASSERT(pTextDoc);
2245 SwDoc* pDoc(pTextDoc->GetDocShell()->GetDoc());
2246 SwRootFrame* pLayout(pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
2247 CPPUNIT_ASSERT(!pLayout->IsHideRedlines());
2248
2249 xmlDocPtr pXmlDoc = parseLayoutDump();
2250
2251 // check footnotes
2252 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn", 6);
2253 assertXPath(pXmlDoc, "/root/page[2]/ftncont/ftn", 3);
2254 // check that first page ends with the y line and second page starts with z
2255 assertXPath(pXmlDoc, "/root/page[1]/body/txt[last()]/LineBreak[last()]", "Line",
2256 "yyyyyyyyy yyy yyyyyyyyyyyyyyyy yyyyyyy yyy yyyyy yyyyyyyyy yyy yyyyyyyyy ");
2257 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/LineBreak[1]", "Line",
2258 "zzz. zzz zzzz zzzz7 zzz zzz zzzzzzz zzz zzzz zzzzzzzzzzzzzz zzzzzzzzzzzz ");
2259
2260 // hide redlines - all still visible footnotes move to page 1
2261 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2262
2263 discardDumpedLayout();
2264 pXmlDoc = parseLayoutDump();
2265
2266 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn", 2);
2267 assertXPath(pXmlDoc, "/root/page[2]/ftncont/ftn", 0);
2268
2269 // show again - should now get the same result as on loading
2270 lcl_dispatchCommand(mxComponent, ".uno:ShowTrackedChanges", {});
2271
2272 discardDumpedLayout();
2273 pXmlDoc = parseLayoutDump();
2274
2275 // check footnotes
2276 assertXPath(pXmlDoc, "/root/page[1]/ftncont/ftn", 6);
2277 assertXPath(pXmlDoc, "/root/page[2]/ftncont/ftn", 3);
2278 // check that first page ends with the y line and second page starts with z
2279 assertXPath(pXmlDoc, "/root/page[1]/body/txt[last()]/LineBreak[last()]", "Line",
2280 "yyyyyyyyy yyy yyyyyyyyyyyyyyyy yyyyyyy yyy yyyyy yyyyyyyyy yyy yyyyyyyyy ");
2281 assertXPath(pXmlDoc, "/root/page[2]/body/txt[1]/LineBreak[1]", "Line",
2282 "zzz. zzz zzzz zzzz7 zzz zzz zzzzzzz zzz zzzz zzzzzzzzzzzzzz zzzzzzzzzzzz ");
2283 }
2284
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testRedlineNumberInNumbering)2285 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testRedlineNumberInNumbering)
2286 {
2287 SwDoc* pDoc = createDoc("tdf42748.fodt");
2288 SwDocShell* pShell = pDoc->GetDocShell();
2289
2290 // Dump the rendering of the first page as an XML file.
2291 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2292 MetafileXmlDump dumper;
2293
2294 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2295 CPPUNIT_ASSERT(pXmlDoc);
2296
2297 // Assert the tracked deletion of the number of joined list item and
2298 // the tracked insertion of the number after a split list item as not black elements
2299 assertXPath(pXmlDoc, "/metafile/push/push/push/textcolor[not(@color='#000000')]", 6);
2300 }
2301
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf125300)2302 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf125300)
2303 {
2304 SwDoc* pDoc = createDoc("tdf125300.docx");
2305 SwDocShell* pShell = pDoc->GetDocShell();
2306
2307 // Dump the rendering of the first page as an XML file.
2308 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2309 MetafileXmlDump dumper;
2310
2311 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2312 CPPUNIT_ASSERT(pXmlDoc);
2313
2314 // Keep line spacing before bottom cell border (it was 1892)
2315 assertXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[5]/polyline/point[@y='2092']", 2);
2316 }
2317
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf116830)2318 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf116830)
2319 {
2320 SwDoc* pDoc = createDoc("tdf116830.odt");
2321 SwDocShell* pShell = pDoc->GetDocShell();
2322
2323 // Dump the rendering of the first page as an XML file.
2324 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2325 MetafileXmlDump dumper;
2326 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2327 CPPUNIT_ASSERT(pXmlDoc);
2328
2329 // Assert that the yellow rectangle (cell background) is painted after the
2330 // polypolygon (background shape).
2331 // Background shape: 1.1.1.2
2332 // Cell background: 1.1.1.3
2333 assertXPath(
2334 pXmlDoc,
2335 "/metafile/push[1]/push[1]/push[1]/push[2]/push[1]/push[1]/fillcolor[@color='#729fcf']", 1);
2336 assertXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[2]/push[1]/push[1]/polypolygon",
2337 1);
2338
2339 // This failed: cell background was painted before the background shape.
2340 assertXPath(pXmlDoc,
2341 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/fillcolor[@color='#ffff00']", 1);
2342 assertXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/rect", 1);
2343 }
2344
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf114163)2345 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf114163)
2346 {
2347 SwDoc* pDoc = createDoc("tdf114163.odt");
2348 SwDocShell* pShell = pDoc->GetDocShell();
2349
2350 // Dump the rendering of the first page as an XML file.
2351 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2352 MetafileXmlDump dumper;
2353 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2354 CPPUNIT_ASSERT(pXmlDoc);
2355
2356 assertXPathContent(
2357 pXmlDoc,
2358 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/textarray[12]/text",
2359 "Data3");
2360 // This failed, if the legend first label is not "Data3". The legend position is right.
2361 }
2362
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf125335)2363 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf125335)
2364 {
2365 SwDoc* pDoc = createDoc("tdf125335.odt");
2366 SwDocShell* pShell = pDoc->GetDocShell();
2367
2368 // Dump the rendering of the first page as an XML file.
2369 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2370 MetafileXmlDump dumper;
2371 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2372 CPPUNIT_ASSERT(pXmlDoc);
2373
2374 assertXPathContent(
2375 pXmlDoc,
2376 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/textarray[12]/text",
2377 "Data3");
2378 // This failed, if the legend first label is not "Data3". The legend position is bottom.
2379 }
2380
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf75659)2381 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf75659)
2382 {
2383 SwDoc* pDoc = createDoc("tdf75659.docx");
2384 SwDocShell* pShell = pDoc->GetDocShell();
2385
2386 // Dump the rendering of the first page as an XML file.
2387 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2388 MetafileXmlDump dumper;
2389 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2390 CPPUNIT_ASSERT(pXmlDoc);
2391
2392 assertXPathContent(
2393 pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/textarray[17]/text", "Series1");
2394
2395 assertXPathContent(
2396 pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/textarray[18]/text", "Series2");
2397
2398 assertXPathContent(
2399 pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/textarray[19]/text", "Series3");
2400 // These failed, if the legend names are empty strings.
2401 }
2402
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf123268)2403 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf123268)
2404 {
2405 SwDoc* pDoc = createDoc("tdf123268.odt");
2406 SwDocShell* pShell = pDoc->GetDocShell();
2407
2408 // Dump the rendering of the first page as an XML file.
2409 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2410 MetafileXmlDump dumper;
2411 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2412 CPPUNIT_ASSERT(pXmlDoc);
2413 // Without the accompanying fix in place, this test would have failed with:
2414 // - Expected: 41
2415 // - Actual : 0
2416 // i.e. the chart lost.
2417 assertXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/push",
2418 41);
2419 }
2420
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf115630)2421 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf115630)
2422 {
2423 SwDoc* pDoc = createDoc("tdf115630.docx");
2424 SwDocShell* pShell = pDoc->GetDocShell();
2425
2426 // Dump the rendering of the first page as an XML file.
2427 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2428 MetafileXmlDump dumper;
2429 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2430 CPPUNIT_ASSERT(pXmlDoc);
2431
2432 // Test wide of inner chart area.
2433 sal_Int32 nXRight
2434 = getXPath(pXmlDoc,
2435 "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/push[3]/polyline[1]/point[1]",
2436 "x")
2437 .toInt32();
2438 sal_Int32 nXLeft
2439 = getXPath(pXmlDoc,
2440 "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/push[3]/polyline[1]/point[2]",
2441 "x")
2442 .toInt32();
2443 CPPUNIT_ASSERT_DOUBLES_EQUAL(2895, nXRight - nXLeft, 50);
2444 }
2445
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf108021)2446 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf108021)
2447 {
2448 SwDoc* pDoc = createDoc("tdf108021.odt");
2449 SwDocShell* pShell = pDoc->GetDocShell();
2450
2451 // Dump the rendering of the first page as an XML file.
2452 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2453 MetafileXmlDump dumper;
2454 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2455 CPPUNIT_ASSERT(pXmlDoc);
2456
2457 assertXPath(
2458 pXmlDoc,
2459 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/textarray[@length='22']",
2460 8);
2461 // This failed, if the textarray length of the first axis label not 22.
2462 }
2463
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf125334)2464 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf125334)
2465 {
2466 SwDoc* pDoc = createDoc("tdf125334.odt");
2467 SwDocShell* pShell = pDoc->GetDocShell();
2468
2469 // Dump the rendering of the first page as an XML file.
2470 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2471 MetafileXmlDump dumper;
2472 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2473 CPPUNIT_ASSERT(pXmlDoc);
2474
2475 assertXPath(
2476 pXmlDoc,
2477 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/textarray[@length='17']",
2478 4);
2479 // This failed, if the textarray length of the category axis label not 17.
2480 }
2481
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf122800)2482 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf122800)
2483 {
2484 SwDoc* pDoc = createDoc("tdf122800.odt");
2485 SwDocShell* pShell = pDoc->GetDocShell();
2486
2487 // Dump the rendering of the first page as an XML file.
2488 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2489 MetafileXmlDump dumper;
2490 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2491 CPPUNIT_ASSERT(pXmlDoc);
2492
2493 assertXPath(
2494 pXmlDoc,
2495 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/textarray[@length='22']",
2496 9);
2497 // This failed, if the textarray length of the first axis label not 22.
2498 }
2499
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTruncatedAxisLabel)2500 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTruncatedAxisLabel)
2501 {
2502 SwDoc* pDoc = createDoc("testTruncatedAxisLabel.odt");
2503 SwDocShell* pShell = pDoc->GetDocShell();
2504
2505 // Dump the rendering of the first page as an XML file.
2506 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2507 MetafileXmlDump dumper;
2508 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2509 CPPUNIT_ASSERT(pXmlDoc);
2510
2511 // test the X axis label visibility
2512 assertXPathContent(
2513 pXmlDoc,
2514 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/textarray[1]/text",
2515 "Long axis label truncated 1");
2516
2517 // test the Y axis label visibility
2518 assertXPathContent(
2519 pXmlDoc,
2520 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/textarray[3]/text",
2521 "-5.00");
2522 }
2523
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf128996)2524 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf128996)
2525 {
2526 SwDoc* pDoc = createDoc("tdf128996.docx");
2527 SwDocShell* pShell = pDoc->GetDocShell();
2528
2529 // Dump the rendering of the first page as an XML file.
2530 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2531 MetafileXmlDump dumper;
2532 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2533 CPPUNIT_ASSERT(pXmlDoc);
2534
2535 assertXPathContent(pXmlDoc,
2536 "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/textarray[1]/text",
2537 "A very long category name 1");
2538 }
2539
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf126244)2540 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf126244)
2541 {
2542 SwDoc* pDoc = createDoc("tdf126244.docx");
2543 SwDocShell* pShell = pDoc->GetDocShell();
2544
2545 // Dump the rendering of the first page as an XML file.
2546 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2547 MetafileXmlDump dumper;
2548 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2549 CPPUNIT_ASSERT(pXmlDoc);
2550 // Test the first level of vertical category axis labels orientation. The first level orientation should be horizontal.
2551 assertXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/font[1]", "orientation",
2552 "0");
2553 // Test the second level of vertical category axis labels orientation. The second level orientation should be vertical.
2554 assertXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/font[5]", "orientation",
2555 "900");
2556 // Test the third level of vertical category axis labels orientation. The third level orientation should be vertical.
2557 assertXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/font[7]", "orientation",
2558 "900");
2559 }
2560
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf127304)2561 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf127304)
2562 {
2563 SwDoc* pDoc = createDoc("tdf127304.odt");
2564 SwDocShell* pShell = pDoc->GetDocShell();
2565
2566 // Dump the rendering of the first page as an XML file.
2567 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2568 MetafileXmlDump dumper;
2569 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2570 CPPUNIT_ASSERT(pXmlDoc);
2571 // Test the first level of horizontal category axis labels orientation. The first level orientation should be vertical.
2572 assertXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/font[1]", "orientation",
2573 "900");
2574 // Test the second level of horizontal category axis labels orientation. The second level orientation should be horizontal.
2575 assertXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/font[5]", "orientation",
2576 "0");
2577 // Test the third level of horizontal category axis labels orientation. The third level orientation should be horizontal.
2578 assertXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/font[7]", "orientation",
2579 "0");
2580 }
2581
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testHorizontal_multilevel)2582 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testHorizontal_multilevel)
2583 {
2584 SwDoc* pDoc = createDoc("horizontal_multilevel.odt");
2585 SwDocShell* pShell = pDoc->GetDocShell();
2586
2587 // Dump the rendering of the first page as an XML file.
2588 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2589 MetafileXmlDump dumper;
2590 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2591 CPPUNIT_ASSERT(pXmlDoc);
2592 // Test the Y position of horizontal category axis label.
2593 sal_Int32 nYposition
2594 = getXPath(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/textarray[7]", "y")
2595 .toInt32();
2596 CPPUNIT_ASSERT(nYposition > 7943 && nYposition < 7947);
2597 }
2598
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf124796)2599 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf124796)
2600 {
2601 SwDoc* pDoc = createDoc("tdf124796.odt");
2602 SwDocShell* pShell = pDoc->GetDocShell();
2603
2604 // Dump the rendering of the first page as an XML file.
2605 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2606 MetafileXmlDump dumper;
2607 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2608 CPPUNIT_ASSERT(pXmlDoc);
2609
2610 // This failed, if the minimum value of Y axis is not -10.
2611 assertXPathContent(
2612 pXmlDoc,
2613 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/textarray[5]/text",
2614 "-10");
2615
2616 // This failed, if the maximum value of Y axis is not 15.
2617 assertXPathContent(
2618 pXmlDoc,
2619 "/metafile/push[1]/push[1]/push[1]/push[3]/push[1]/push[1]/push[1]/textarray[10]/text",
2620 "15");
2621 }
2622
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf129054)2623 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf129054)
2624 {
2625 SwDoc* pDoc = createDoc("tdf129054.docx");
2626 SwDocShell* pShell = pDoc->GetDocShell();
2627
2628 // Dump the rendering of the first page as an XML file.
2629 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2630 MetafileXmlDump dumper;
2631 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2632 CPPUNIT_ASSERT(pXmlDoc);
2633
2634 // Test the size of diameter of Pie chart.
2635 sal_Int32 nYTop
2636 = getXPath(pXmlDoc,
2637 "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/push[4]/polyline[1]/point[1]",
2638 "y")
2639 .toInt32();
2640 sal_Int32 nYBottom
2641 = getXPath(
2642 pXmlDoc,
2643 "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/push[4]/polyline[1]/point[31]",
2644 "y")
2645 .toInt32();
2646 CPPUNIT_ASSERT_EQUAL(sal_Int32(4810), nYTop - nYBottom);
2647 }
2648
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf129173)2649 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf129173)
2650 {
2651 SwDoc* pDoc = createDoc("testAreaChartNumberFormat.docx");
2652 SwDocShell* pShell = pDoc->GetDocShell();
2653
2654 // Dump the rendering of the first page as an XML file.
2655 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2656 MetafileXmlDump dumper;
2657 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2658 CPPUNIT_ASSERT(pXmlDoc);
2659
2660 // Check the first data label of area chart.
2661 assertXPathContent(
2662 pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/textarray[22]/text", "56");
2663 }
2664
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf129095)2665 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf129095)
2666 {
2667 SwDoc* pDoc = createDoc("tdf129095.docx");
2668 SwDocShell* pShell = pDoc->GetDocShell();
2669
2670 // Dump the rendering of the first page as an XML file.
2671 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2672 MetafileXmlDump dumper;
2673 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2674 CPPUNIT_ASSERT(pXmlDoc);
2675
2676 // check the inner chart area (relative size) visibility with testing the X axis label
2677 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/textarray/text",
2678 "Category 1");
2679 }
2680
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf132956)2681 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf132956)
2682 {
2683 SwDoc* pDoc = createDoc("tdf132956.docx");
2684 SwDocShell* pShell = pDoc->GetDocShell();
2685
2686 // Dump the rendering of the first page as an XML file.
2687 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2688 MetafileXmlDump dumper;
2689 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2690 CPPUNIT_ASSERT(pXmlDoc);
2691
2692 // check the inner chart area (default size) visibility with testing the X axis label
2693 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/textarray/text",
2694 "Category 1");
2695 }
2696
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf116925)2697 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf116925)
2698 {
2699 SwDoc* pDoc = createDoc("tdf116925.docx");
2700 SwDocShell* pShell = pDoc->GetDocShell();
2701
2702 // Dump the rendering of the first page as an XML file.
2703 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2704 MetafileXmlDump dumper;
2705 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2706 CPPUNIT_ASSERT(pXmlDoc);
2707
2708 assertXPathContent(pXmlDoc,
2709 "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/push[3]/textarray/text",
2710 "hello");
2711 // This failed, text color was #000000.
2712 assertXPath(
2713 pXmlDoc,
2714 "/metafile/push[1]/push[1]/push[1]/push[4]/push[1]/push[3]/textcolor[@color='#ffffff']", 1);
2715 }
2716
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf117028)2717 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf117028)
2718 {
2719 SwDoc* pDoc = createDoc("tdf117028.docx");
2720 SwDocShell* pShell = pDoc->GetDocShell();
2721
2722 // Dump the rendering of the first page as an XML file.
2723 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2724 MetafileXmlDump dumper;
2725 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2726 CPPUNIT_ASSERT(pXmlDoc);
2727
2728 // The only polypolygon in the rendering result was the white background we
2729 // want to avoid.
2730 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//polypolygon");
2731 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
2732 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes));
2733 xmlXPathFreeObject(pXmlObj);
2734
2735 // Make sure the text is still rendered.
2736 assertXPathContent(pXmlDoc, "//textarray/text", "Hello");
2737 }
2738
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf106390)2739 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf106390)
2740 {
2741 SwDoc* pDoc = createDoc("tdf106390.odt");
2742 SwDocShell* pShell = pDoc->GetDocShell();
2743
2744 // Dump the rendering of the first page as an XML file.
2745 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2746 MetafileXmlDump dumper;
2747 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2748 CPPUNIT_ASSERT(pXmlDoc);
2749 sal_Int32 nBottom = getXPath(pXmlDoc, "//sectrectclipregion", "bottom").toInt32();
2750
2751 // No end point of line segments shall go below the bottom of the clipping area.
2752 const OString sXPath = "//polyline/point[@y>" + OString::number(nBottom) + "]";
2753
2754 assertXPath(pXmlDoc, sXPath, 0);
2755 }
2756
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTableExtrusion1)2757 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTableExtrusion1)
2758 {
2759 SwDoc* pDoc = createDoc("table-extrusion1.odt");
2760 SwDocShell* pShell = pDoc->GetDocShell();
2761
2762 // Dump the rendering of the first page as an XML file.
2763 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2764 MetafileXmlDump dumper;
2765 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2766 CPPUNIT_ASSERT(pXmlDoc);
2767 sal_Int32 nRight = getXPath(pXmlDoc, "//sectrectclipregion", "right").toInt32();
2768 sal_Int32 nLeft = static_cast<sal_Int32>(nRight * 0.95);
2769
2770 // Expect table borders in right page margin.
2771 const OString sXPath = "//polyline/point[@x>" + OString::number(nLeft) + " and @x<"
2772 + OString::number(nRight) + "]";
2773
2774 assertXPath(pXmlDoc, sXPath, 4);
2775 }
2776
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTableExtrusion2)2777 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTableExtrusion2)
2778 {
2779 SwDoc* pDoc = createDoc("table-extrusion2.odt");
2780 SwDocShell* pShell = pDoc->GetDocShell();
2781
2782 // Dump the rendering of the first page as an XML file.
2783 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
2784 MetafileXmlDump dumper;
2785 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
2786 CPPUNIT_ASSERT(pXmlDoc);
2787 // End point position of the outer table.
2788 sal_Int32 nX = getXPath(pXmlDoc, "(//polyline[1]/point)[2]", "x").toInt32();
2789
2790 // Do not allow inner table extrude outer table.
2791 const OString sXPath = "//polyline/point[@x>" + OString::number(nX) + "]";
2792
2793 assertXPath(pXmlDoc, sXPath, 0);
2794 }
2795
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf116848)2796 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf116848)
2797 {
2798 SwDoc* pDoc = createDoc("tdf116848.odt");
2799 // This resulted in a layout loop.
2800 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2801 }
2802
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf117245)2803 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf117245)
2804 {
2805 createDoc("tdf117245.odt");
2806 xmlDocPtr pXmlDoc = parseLayoutDump();
2807 // This was 2, TabOverMargin did not use a single line when there was
2808 // enough space for the text.
2809 assertXPath(pXmlDoc, "/root/page/body/txt[1]/LineBreak", 1);
2810
2811 // This was 2, same problem elsewhere due to code duplication.
2812 assertXPath(pXmlDoc, "/root/page/body/txt[2]/LineBreak", 1);
2813 }
2814
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf118672)2815 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf118672)
2816 {
2817 createDoc("tdf118672.odt");
2818 xmlDocPtr pXmlDoc = parseLayoutDump();
2819
2820 // Check if we have hyphenation support, otherwise can't test SwHyphPortion.
2821 uno::Reference<linguistic2::XLinguServiceManager2> xLinguServiceManager
2822 = linguistic2::LinguServiceManager::create(comphelper::getProcessComponentContext());
2823 uno::Sequence<lang::Locale> aLocales
2824 = xLinguServiceManager->getAvailableLocales("com.sun.star.linguistic2.Hyphenator");
2825 if (std::none_of(aLocales.begin(), aLocales.end(), [](const lang::Locale& rLocale) {
2826 return rLocale.Language == "en" && rLocale.Country == "US";
2827 }))
2828 return;
2829
2830 const OUString aLine1(
2831 "He heard quiet steps behind him. That didn't bode well. Who could be fol*1 2 "
2832 "3 4 5 6 7 8 9 10con-");
2833 // This ended as "fol*1 2 3 4 5 6 7 8 9", i.e. "10con-" was moved to the next line.
2834 assertXPath(pXmlDoc, "/root/page/body/txt[1]/LineBreak[1]", "Line", aLine1);
2835 const OUString aLine2("setetur");
2836 assertXPath(pXmlDoc, "/root/page/body/txt[1]/LineBreak[2]", "Line", aLine2);
2837 }
2838
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf117923)2839 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf117923)
2840 {
2841 createDoc("tdf117923.doc");
2842 // Ensure that all text portions are calculated before testing.
2843 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2844 CPPUNIT_ASSERT(pTextDoc);
2845 SwViewShell* pViewShell
2846 = pTextDoc->GetDocShell()->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
2847 CPPUNIT_ASSERT(pViewShell);
2848 pViewShell->Reformat();
2849
2850 xmlDocPtr pXmlDoc = parseLayoutDump();
2851
2852 // Check that we actually test the line we need
2853 assertXPathContent(pXmlDoc, "/root/page/body/tab/row/cell/txt[3]", "GHI GHI GHI GHI");
2854 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/txt[3]/Special", "nType",
2855 "PortionType::Number");
2856 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/txt[3]/Special", "rText", "2.");
2857 // The numbering height was 960.
2858 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/txt[3]/Special", "nHeight", "220");
2859 }
2860
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf127606)2861 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf127606)
2862 {
2863 createDoc("tdf117923.docx");
2864 // Ensure that all text portions are calculated before testing.
2865 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2866 CPPUNIT_ASSERT(pTextDoc);
2867 SwViewShell* pViewShell
2868 = pTextDoc->GetDocShell()->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
2869 CPPUNIT_ASSERT(pViewShell);
2870 pViewShell->Reformat();
2871
2872 xmlDocPtr pXmlDoc = parseLayoutDump();
2873
2874 // Check that we actually test the line we need
2875 assertXPathContent(pXmlDoc, "/root/page/body/tab/row/cell/txt[3]", "GHI GHI GHI GHI");
2876 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/txt[3]/Special", "nType",
2877 "PortionType::Number");
2878 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/txt[3]/Special", "rText", "2.");
2879 // The numbering height was 960 in DOC format.
2880 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/txt[3]/Special", "nHeight", "220");
2881
2882 // tdf#127606: now it's possible to change formatting of numbering
2883 // increase font size (220 -> 260)
2884 lcl_dispatchCommand(mxComponent, ".uno:SelectAll", {});
2885 lcl_dispatchCommand(mxComponent, ".uno:Grow", {});
2886 pViewShell->Reformat();
2887 discardDumpedLayout();
2888 pXmlDoc = parseLayoutDump();
2889 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/txt[3]/Special", "nHeight", "260");
2890 }
2891
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf109077)2892 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf109077)
2893 {
2894 createDoc("tdf109077.docx");
2895 xmlDocPtr pXmlDoc = parseLayoutDump();
2896 sal_Int32 nShapeTop
2897 = getXPath(pXmlDoc, "//anchored/SwAnchoredDrawObject/bounds", "top").toInt32();
2898 sal_Int32 nTextBoxTop = getXPath(pXmlDoc, "//anchored/fly/infos/bounds", "top").toInt32();
2899 // This was 281: the top of the shape and its textbox should match, though
2900 // tolerate differences <= 1px (about 15 twips).
2901 CPPUNIT_ASSERT_LESS(static_cast<sal_Int32>(15), nTextBoxTop - nShapeTop);
2902 }
2903
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testUserFieldTypeLanguage)2904 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testUserFieldTypeLanguage)
2905 {
2906 // Set the system locale to German, the document will be English.
2907 SvtSysLocaleOptions aOptions;
2908 OUString sLocaleConfigString = aOptions.GetLanguageTag().getBcp47();
2909 aOptions.SetLocaleConfigString("de-DE");
2910 aOptions.Commit();
2911 comphelper::ScopeGuard g([&aOptions, &sLocaleConfigString] {
2912 aOptions.SetLocaleConfigString(sLocaleConfigString);
2913 aOptions.Commit();
2914 });
2915
2916 SwDoc* pDoc = createDoc("user-field-type-language.fodt");
2917 SwViewShell* pViewShell = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
2918 pViewShell->UpdateFields();
2919 xmlDocPtr pXmlDoc = parseLayoutDump();
2920 // This was "123,456.00", via a buggy 1234.56 -> 1234,56 -> 123456 ->
2921 // 123,456.00 transform chain.
2922 assertXPath(pXmlDoc, "/root/page/body/txt/Special[@nType='PortionType::Field']", "rText",
2923 "1,234.56");
2924 }
2925
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf109137)2926 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf109137)
2927 {
2928 createDoc("tdf109137.docx");
2929 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
2930 utl::TempFile aTempFile;
2931 aTempFile.EnableKillingFile();
2932 uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence({
2933 { "FilterName", uno::Any(OUString("writer8")) },
2934 }));
2935 xStorable->storeToURL(aTempFile.GetURL(), aDescriptor);
2936 loadURL(aTempFile.GetURL(), "tdf109137.odt");
2937 xmlDocPtr pXmlDoc = parseLayoutDump();
2938 // This was 0, the blue rectangle moved from the 1st to the 2nd page.
2939 assertXPath(pXmlDoc, "/root/page[1]/body/txt/anchored/fly/notxt",
2940 /*nNumberOfNodes=*/1);
2941 }
2942
2943 //just care it doesn't crash/assert
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testForcepoint72)2944 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint72) { createDoc("forcepoint72-1.rtf"); }
2945
2946 //just care it doesn't crash/assert
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testForcepoint75)2947 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint75) { createDoc("forcepoint75-1.rtf"); }
2948
2949 //just care it doesn't crash/assert
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testForcepointFootnoteFrame)2950 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepointFootnoteFrame)
2951 {
2952 createDoc("forcepoint-swfootnoteframe-1.rtf");
2953 }
2954
2955 //FIXME: disabled after failing again with fixed layout
2956 //CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testForcepoint76) { createDoc("forcepoint76-1.rtf"); }
2957
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf118058)2958 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf118058)
2959 {
2960 SwDoc* pDoc = createDoc("tdf118058.fodt");
2961 // This resulted in a layout loop.
2962 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2963 }
2964
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf128611)2965 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf128611)
2966 {
2967 createDoc("tdf128611.fodt");
2968 xmlDocPtr pXmlDoc = parseLayoutDump();
2969 CPPUNIT_ASSERT(pXmlDoc);
2970 // Without the accompanying fix in place, this test would have failed with:
2971 // - Expected: 1
2972 // - Actual : 14
2973 // i.e. there were multiple portions in the first paragraph of the A1 cell, which means that the
2974 // rotated text was broken into multiple lines without a good reason.
2975 assertXPath(pXmlDoc, "//tab/row/cell[1]/txt/Text", "Portion", "Abcd efghijkl");
2976 }
2977
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf117188)2978 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf117188)
2979 {
2980 createDoc("tdf117188.docx");
2981 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
2982 utl::TempFile aTempFile;
2983 aTempFile.EnableKillingFile();
2984 uno::Sequence<beans::PropertyValue> aDescriptor(comphelper::InitPropertySequence({
2985 { "FilterName", uno::Any(OUString("writer8")) },
2986 }));
2987 xStorable->storeToURL(aTempFile.GetURL(), aDescriptor);
2988 loadURL(aTempFile.GetURL(), "tdf117188.odt");
2989 xmlDocPtr pXmlDoc = parseLayoutDump();
2990 OUString sWidth = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "width");
2991 OUString sHeight = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "height");
2992 // The text box must have zero border distances
2993 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "left", "0");
2994 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "top", "0");
2995 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "width", sWidth);
2996 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/prtBounds", "height", sHeight);
2997 }
2998
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf117187)2999 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf117187)
3000 {
3001 createDoc("tdf117187.odt");
3002 xmlDocPtr pXmlDoc = parseLayoutDump();
3003
3004 // there should be no fly portions
3005 assertXPath(pXmlDoc, "/root/page/body/txt/Special[@nType='PortionType::Fly']", 0);
3006 }
3007
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf119875)3008 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf119875)
3009 {
3010 createDoc("tdf119875.odt");
3011 xmlDocPtr pXmlDoc = parseLayoutDump();
3012 sal_Int32 nFirstTop
3013 = getXPath(pXmlDoc, "/root/page[2]/body/section[1]/infos/bounds", "top").toInt32();
3014 sal_Int32 nSecondTop
3015 = getXPath(pXmlDoc, "/root/page[2]/body/section[2]/infos/bounds", "top").toInt32();
3016 // The first section had the same top value as the second one, so they
3017 // overlapped.
3018 CPPUNIT_ASSERT_LESS(nSecondTop, nFirstTop);
3019 }
3020
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf120287)3021 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf120287)
3022 {
3023 createDoc("tdf120287.fodt");
3024 xmlDocPtr pXmlDoc = parseLayoutDump();
3025 // This was 2, TabOverMargin Word-specific compat flag did not imply
3026 // default-in-Word printer-independent layout, resulting in an additional
3027 // line break.
3028 assertXPath(pXmlDoc, "/root/page/body/txt[1]/LineBreak", 1);
3029 }
3030
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf120287b)3031 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf120287b)
3032 {
3033 createDoc("tdf120287b.fodt");
3034 xmlDocPtr pXmlDoc = parseLayoutDump();
3035 // This was 1418, TabOverMargin did the right split of the paragraph to two
3036 // lines, but then calculated a too large tab portion size on the first
3037 // line.
3038 assertXPath(pXmlDoc, "/root/page/body/txt[1]/Text[@nType='PortionType::TabRight']", "nWidth",
3039 "17");
3040 }
3041
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf120287c)3042 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf120287c)
3043 {
3044 createDoc("tdf120287c.fodt");
3045 xmlDocPtr pXmlDoc = parseLayoutDump();
3046 // This was 2, the second line was not broken into a 2nd and a 3rd one,
3047 // rendering text outside the paragraph frame.
3048 assertXPath(pXmlDoc, "/root/page/body/txt[1]/LineBreak", 3);
3049 }
3050
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf122878)3051 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf122878)
3052 {
3053 createDoc("tdf122878.docx");
3054 xmlDocPtr pXmlDoc = parseLayoutDump();
3055 // FIXME: the XPath should be adjusted when the proper floating table would be imported
3056 const sal_Int32 nTblTop
3057 = getXPath(pXmlDoc, "/root/page[1]/footer/txt/anchored/fly/tab/infos/bounds", "top")
3058 .toInt32();
3059 const sal_Int32 nFirstPageParaCount
3060 = getXPathContent(pXmlDoc, "count(/root/page[1]/body/txt)").toInt32();
3061 CPPUNIT_ASSERT_EQUAL(sal_Int32(30), nFirstPageParaCount);
3062 for (sal_Int32 i = 1; i <= nFirstPageParaCount; ++i)
3063 {
3064 const OString xPath = "/root/page[1]/body/txt[" + OString::number(i) + "]/infos/bounds";
3065 const sal_Int32 nTxtBottom = getXPath(pXmlDoc, xPath.getStr(), "top").toInt32()
3066 + getXPath(pXmlDoc, xPath.getStr(), "height").toInt32();
3067 // No body paragraphs should overlap the table in the footer
3068 CPPUNIT_ASSERT_MESSAGE(OString("testing paragraph #" + OString::number(i)).getStr(),
3069 nTxtBottom <= nTblTop);
3070 }
3071 }
3072
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf115094)3073 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf115094)
3074 {
3075 createDoc("tdf115094.docx");
3076 xmlDocPtr pXmlDoc = parseLayoutDump();
3077
3078 sal_Int32 nTopOfD1
3079 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/infos/bounds",
3080 "top")
3081 .toInt32();
3082 sal_Int32 nTopOfD1Anchored = getXPath(pXmlDoc,
3083 "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/"
3084 "txt[2]/anchored/fly/infos/bounds",
3085 "top")
3086 .toInt32();
3087 CPPUNIT_ASSERT_LESS(nTopOfD1Anchored, nTopOfD1);
3088 sal_Int32 nTopOfB2
3089 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/infos/bounds",
3090 "top")
3091 .toInt32();
3092 sal_Int32 nTopOfB2Anchored = getXPath(pXmlDoc,
3093 "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/"
3094 "txt[1]/anchored/fly/infos/bounds",
3095 "top")
3096 .toInt32();
3097 CPPUNIT_ASSERT_LESS(nTopOfB2Anchored, nTopOfB2);
3098 }
3099
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf122607)3100 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf122607)
3101 {
3102 createDoc("tdf122607.odt");
3103 xmlDocPtr pXmlDoc = parseLayoutDump();
3104 assertXPath(pXmlDoc,
3105 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
3106 "fly/txt/Text[1]",
3107 "nHeight", "253");
3108 assertXPath(pXmlDoc,
3109 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
3110 "fly/txt/Text[1]",
3111 "nWidth", "428");
3112 assertXPath(pXmlDoc,
3113 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
3114 "fly/txt/Text[1]",
3115 "Portion", "Fax:");
3116 }
3117
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf122607_regression)3118 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf122607_regression)
3119 {
3120 discardDumpedLayout();
3121 if (mxComponent.is())
3122 mxComponent->dispose();
3123
3124 OUString const pName("tdf122607_leerzeile.odt");
3125
3126 OUString const url(m_directories.getURLFromSrc(DATA_DIRECTORY) + pName);
3127
3128 // note: must set Hidden property, so that SfxFrameViewWindow_Impl::Resize()
3129 // does *not* forward initial VCL Window Resize and thereby triggers a
3130 // layout which does not happen on soffice --convert-to pdf.
3131 std::vector<beans::PropertyValue> aFilterOptions = {
3132 { beans::PropertyValue("Hidden", -1, uno::Any(true), beans::PropertyState_DIRECT_VALUE) },
3133 };
3134
3135 std::cout << pName << ":\n";
3136
3137 // inline the loading because currently properties can't be passed...
3138 mxComponent = loadFromDesktop(url, "com.sun.star.text.TextDocument",
3139 comphelper::containerToSequence(aFilterOptions));
3140
3141 CPPUNIT_ASSERT(mxComponent.is());
3142
3143 uno::Sequence<beans::PropertyValue> props(comphelper::InitPropertySequence({
3144 { "FilterName", uno::Any(OUString("writer_pdf_Export")) },
3145 }));
3146 utl::TempFile aTempFile;
3147 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
3148 xStorable->storeToURL(aTempFile.GetURL(), props);
3149
3150 xmlDocPtr pXmlDoc = parseLayoutDump();
3151 // somehow these 2 rows overlapped in the PDF unless CalcLayout() runs
3152 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "mbFixSize",
3153 "false");
3154 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "top", "2977");
3155 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "height", "241");
3156 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "mbFixSize",
3157 "true");
3158 // this was 3034, causing the overlap
3159 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "top", "3218");
3160 assertXPath(pXmlDoc, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "height", "164");
3161
3162 aTempFile.EnableKillingFile();
3163 }
3164
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testBtlrCell)3165 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testBtlrCell)
3166 {
3167 SwDoc* pDoc = createDoc("btlr-cell.odt");
3168 SwDocShell* pShell = pDoc->GetDocShell();
3169
3170 // Dump the rendering of the first page as an XML file.
3171 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
3172 MetafileXmlDump dumper;
3173 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
3174 CPPUNIT_ASSERT(pXmlDoc);
3175
3176 // Without the accompanying fix in place, this test would have failed, as
3177 // the orientation was 0 (layout did not take btlr direction request from
3178 // doc model).
3179 assertXPath(pXmlDoc, "//font[1]", "orientation", "900");
3180
3181 #if !defined(MACOSX) && !defined(_WIN32) // macOS fails with x == 2662 for some reason.
3182 // Without the accompanying fix in place, this test would have failed with 'Expected: 1915;
3183 // Actual : 1756', i.e. the AAA1 text was too close to the left cell border due to an ascent vs
3184 // descent mismatch when calculating the baseline offset of the text portion.
3185 assertXPath(pXmlDoc, "//textarray[1]", "x", "1915");
3186 assertXPath(pXmlDoc, "//textarray[1]", "y", "2707");
3187
3188 // Without the accompanying fix in place, this test would have failed with 'Expected: 1979;
3189 // Actual : 2129', i.e. the gray background of the "AAA2." text was too close to the right edge
3190 // of the text portion. Now it's exactly behind the text portion.
3191 assertXPath(pXmlDoc, "//rect[@top='2159']", "left", "1979");
3192
3193 // Without the accompanying fix in place, this test would have failed with 'Expected: 269;
3194 // Actual : 0', i.e. the AAA2 frame was not visible due to 0 width.
3195 pXmlDoc = parseLayoutDump();
3196 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width", "269");
3197
3198 // Test the position of the cursor after doc load.
3199 // We expect that it's inside the first text frame in the first cell.
3200 // More precisely, this is a bottom to top vertical frame, so we expect it's at the start, which
3201 // means it's at the lower half of the text frame rectangle (vertically).
3202 SwWrtShell* pWrtShell = pShell->GetWrtShell();
3203 CPPUNIT_ASSERT(pWrtShell);
3204
3205 const SwRect& rCharRect = pWrtShell->GetCharRect();
3206 SwTwips nFirstParaTop
3207 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "top").toInt32();
3208 SwTwips nFirstParaHeight
3209 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "height")
3210 .toInt32();
3211 SwTwips nFirstParaMiddle = nFirstParaTop + nFirstParaHeight / 2;
3212 SwTwips nFirstParaBottom = nFirstParaTop + nFirstParaHeight;
3213 // Without the accompanying fix in place, this test would have failed: the lower half (vertical)
3214 // range was 2273 -> 2835, the good vertical position is 2730, the bad one was 1830.
3215 CPPUNIT_ASSERT_GREATER(nFirstParaMiddle, rCharRect.Top());
3216 CPPUNIT_ASSERT_LESS(nFirstParaBottom, rCharRect.Top());
3217
3218 // Save initial cursor position.
3219 SwPosition aCellStart = *pWrtShell->GetCursor()->Start();
3220
3221 // Test that pressing "up" at the start of the cell goes to the next character position.
3222 sal_uLong nNodeIndex = pWrtShell->GetCursor()->Start()->nNode.GetIndex();
3223 sal_Int32 nIndex = pWrtShell->GetCursor()->Start()->nContent.GetIndex();
3224 KeyEvent aKeyEvent(0, KEY_UP);
3225 SwEditWin& rEditWin = pShell->GetView()->GetEditWin();
3226 rEditWin.KeyInput(aKeyEvent);
3227 Scheduler::ProcessEventsToIdle();
3228 // Without the accompanying fix in place, this test would have failed: "up" was interpreted as
3229 // logical "left", which does nothing if you're at the start of the text anyway.
3230 CPPUNIT_ASSERT_EQUAL(nIndex + 1, pWrtShell->GetCursor()->Start()->nContent.GetIndex());
3231
3232 // Test that pressing "right" goes to the next paragraph (logical "down").
3233 sal_Int32 nContentIndex = pWrtShell->GetCursor()->Start()->nContent.GetIndex();
3234 aKeyEvent = KeyEvent(0, KEY_RIGHT);
3235 rEditWin.KeyInput(aKeyEvent);
3236 Scheduler::ProcessEventsToIdle();
3237 // Without the accompanying fix in place, this test would have failed: the cursor went to the
3238 // paragraph after the table.
3239 CPPUNIT_ASSERT_EQUAL(nNodeIndex + 1, pWrtShell->GetCursor()->Start()->nNode.GetIndex());
3240
3241 // Test that we have the correct character index after traveling to the next paragraph.
3242 // Without the accompanying fix in place, this test would have failed: char position was 5, i.e.
3243 // the cursor jumped to the end of the paragraph for no reason.
3244 CPPUNIT_ASSERT_EQUAL(nContentIndex, pWrtShell->GetCursor()->Start()->nContent.GetIndex());
3245
3246 // Test that clicking "below" the second paragraph positions the cursor at the start of the
3247 // second paragraph.
3248 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
3249 SwPosition aPosition(aCellStart);
3250 SwTwips nSecondParaLeft
3251 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "left")
3252 .toInt32();
3253 SwTwips nSecondParaWidth
3254 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width")
3255 .toInt32();
3256 SwTwips nSecondParaTop
3257 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "top").toInt32();
3258 SwTwips nSecondParaHeight
3259 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "height")
3260 .toInt32();
3261 Point aPoint;
3262 aPoint.setX(nSecondParaLeft + nSecondParaWidth / 2);
3263 aPoint.setY(nSecondParaTop + nSecondParaHeight - 100);
3264 SwCursorMoveState aState(MV_NONE);
3265 pLayout->GetCursorOfst(&aPosition, aPoint, &aState);
3266 CPPUNIT_ASSERT_EQUAL(aCellStart.nNode.GetIndex() + 1, aPosition.nNode.GetIndex());
3267 // Without the accompanying fix in place, this test would have failed: character position was 5,
3268 // i.e. cursor was at the end of the paragraph.
3269 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), aPosition.nContent.GetIndex());
3270
3271 // Test that the selection rectangles are inside the cell frame if we select all the cell
3272 // content.
3273 SwTwips nCellLeft
3274 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "left").toInt32();
3275 SwTwips nCellWidth
3276 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "width").toInt32();
3277 SwTwips nCellTop
3278 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "top").toInt32();
3279 SwTwips nCellHeight
3280 = getXPath(pXmlDoc, "/root/page/body/tab/row/cell[1]/infos/bounds", "height").toInt32();
3281 SwRect aCellRect(Point(nCellLeft, nCellTop), Size(nCellWidth, nCellHeight));
3282 pWrtShell->SelAll();
3283 SwShellCursor* pShellCursor = pWrtShell->getShellCursor(/*bBlock=*/false);
3284 CPPUNIT_ASSERT(!pShellCursor->empty());
3285 // Without the accompanying fix in place, this test would have failed with:
3286 // selection rectangle 269x2573@(1970,2172) is not inside cell rectangle 3207x1134@(1593,1701)
3287 // i.e. the selection went past the bottom border of the cell frame.
3288 for (const auto& rRect : *pShellCursor)
3289 {
3290 std::stringstream ss;
3291 ss << "selection rectangle " << rRect << " is not inside cell rectangle " << aCellRect;
3292 CPPUNIT_ASSERT_MESSAGE(ss.str(), aCellRect.IsInside(rRect));
3293 }
3294
3295 // Make sure that the correct rectangle gets repainted on scroll.
3296 SwFrame* pPageFrame = pLayout->GetLower();
3297 CPPUNIT_ASSERT(pPageFrame->IsPageFrame());
3298
3299 SwFrame* pBodyFrame = pPageFrame->GetLower();
3300 CPPUNIT_ASSERT(pBodyFrame->IsBodyFrame());
3301
3302 SwFrame* pTabFrame = pBodyFrame->GetLower();
3303 CPPUNIT_ASSERT(pTabFrame->IsTabFrame());
3304
3305 SwFrame* pRowFrame = pTabFrame->GetLower();
3306 CPPUNIT_ASSERT(pRowFrame->IsRowFrame());
3307
3308 SwFrame* pCellFrame = pRowFrame->GetLower();
3309 CPPUNIT_ASSERT(pCellFrame->IsCellFrame());
3310
3311 SwFrame* pFrame = pCellFrame->GetLower();
3312 CPPUNIT_ASSERT(pFrame->IsTextFrame());
3313
3314 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pFrame);
3315 pTextFrame->SwapWidthAndHeight();
3316 // Mimic what normally SwTextFrame::PaintSwFrame() does:
3317 SwRect aRect(4207, 2273, 269, 572);
3318 pTextFrame->SwitchVerticalToHorizontal(aRect);
3319 // Without the accompanying fix in place, this test would have failed with:
3320 // Expected: 572x269@(1691,4217)
3321 // Actual : 572x269@(2263,4217)
3322 // i.e. the paint rectangle position was incorrect, text was not painted on scrolling up.
3323 CPPUNIT_ASSERT_EQUAL(SwRect(1691, 4217, 572, 269), aRect);
3324 #endif
3325 }
3326
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf123898)3327 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf123898)
3328 {
3329 createDoc("tdf123898.odt");
3330
3331 // Make sure spellchecker has done its job already
3332 Scheduler::ProcessEventsToIdle();
3333
3334 xmlDocPtr pXmlDoc = parseLayoutDump();
3335 // Make sure that the arrow on the left is not there (there are 43 children if it's there)
3336 assertXPathChildren(pXmlDoc, "/root/page/body/txt/anchored/fly/txt", 42);
3337 }
3338
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf123651)3339 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf123651)
3340 {
3341 createDoc("tdf123651.docx");
3342 xmlDocPtr pXmlDoc = parseLayoutDump();
3343 // Without the accompanying fix in place, this test would have failed with 'Expected: 7639;
3344 // Actual: 12926'. The shape was below the second "Lorem ipsum" text, not above it.
3345 assertXPath(pXmlDoc, "//SwAnchoredDrawObject/bounds", "top", "7639");
3346 }
3347
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf116501)3348 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf116501)
3349 {
3350 //just care it doesn't freeze
3351 createDoc("tdf116501.odt");
3352 }
3353
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf118719)3354 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf118719)
3355 {
3356 // Insert a page break.
3357 SwDoc* pDoc = createDoc();
3358 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3359
3360 // Enable hide whitespace mode.
3361 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
3362 aViewOptions.SetHideWhitespaceMode(true);
3363 pWrtShell->ApplyViewOptions(aViewOptions);
3364
3365 pWrtShell->Insert("first");
3366 pWrtShell->InsertPageBreak();
3367 pWrtShell->Insert("second");
3368
3369 // Without the accompanying fix in place, this test would have failed, as the height of the
3370 // first page was 15840 twips, instead of the much smaller 276.
3371 sal_Int32 nOther = parseDump("/root/page[1]/infos/bounds", "height").toInt32();
3372 sal_Int32 nLast = parseDump("/root/page[2]/infos/bounds", "height").toInt32();
3373 CPPUNIT_ASSERT_GREATER(nOther, nLast);
3374 }
3375
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTabOverMargin)3376 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTabOverMargin)
3377 {
3378 createDoc("tab-over-margin.odt");
3379 xmlDocPtr pXmlDoc = parseLayoutDump();
3380
3381 // 2nd paragraph has a tab over the right margin, and with the TabOverMargin compat option,
3382 // there is enough space to have all content in a single line.
3383 // Without the accompanying fix in place, this test would have failed, there were 2 lines.
3384 assertXPath(pXmlDoc, "/root/page/body/txt[2]/LineBreak", 1);
3385 }
3386
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testImageComment)3387 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testImageComment)
3388 {
3389 // Load a document that has "aaa" in it, then a commented image (4th char is the as-char image,
3390 // 5th char is the comment anchor).
3391 SwDoc* pDoc = createDoc("image-comment.odt");
3392 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3393
3394 // Look up a layout position which is on the right of the image.
3395 SwRootFrame* pRoot = pWrtShell->GetLayout();
3396 CPPUNIT_ASSERT(pRoot->GetLower()->IsPageFrame());
3397 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
3398 CPPUNIT_ASSERT(pPage->GetLower()->IsBodyFrame());
3399 SwBodyFrame* pBody = static_cast<SwBodyFrame*>(pPage->GetLower());
3400 CPPUNIT_ASSERT(pBody->GetLower()->IsTextFrame());
3401 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pBody->GetLower());
3402 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
3403 SwSortedObjs& rDrawObjs = *pTextFrame->GetDrawObjs();
3404 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rDrawObjs.size());
3405 SwAnchoredObject* pDrawObj = rDrawObjs[0];
3406 const SwRect& rDrawObjRect = pDrawObj->GetObjRect();
3407 Point aPoint = rDrawObjRect.Center();
3408 aPoint.setX(aPoint.getX() + rDrawObjRect.Width() / 2);
3409
3410 // Ask for the doc model pos of this layout point.
3411 SwPosition aPosition(*pTextFrame->GetTextNodeForFirstText());
3412 pTextFrame->GetCursorOfst(&aPosition, aPoint);
3413
3414 // Without the accompanying fix in place, this test would have failed with:
3415 // - Expected: 5
3416 // - Actual : 4
3417 // i.e. the cursor got positioned between the image and its comment, so typing extended the
3418 // comment, instead of adding content after the commented image.
3419 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(5), aPosition.nContent.GetIndex());
3420 }
3421
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf64222)3422 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf64222)
3423 {
3424 createDoc("tdf64222.docx");
3425 xmlDocPtr pXmlDoc = parseLayoutDump();
3426 assertXPath(pXmlDoc, "/root/page/body/txt[2]/Special", "nHeight", "560");
3427 }
3428
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf113014)3429 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf113014)
3430 {
3431 SwDoc* pDoc = createDoc("tdf113014.fodt");
3432 SwDocShell* pShell = pDoc->GetDocShell();
3433
3434 // Dump the rendering of the first page as an XML file.
3435 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
3436 MetafileXmlDump dumper;
3437 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
3438 CPPUNIT_ASSERT(pXmlDoc);
3439
3440 // This failed, if numbering of cell A1 is missing
3441 // (A1: left indent: 3 cm, first line indent: -3 cm
3442 // A2: left indent: 0 cm, first line indent: 0 cm)
3443 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "1.");
3444 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[3]/text", "2.");
3445 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[5]/text", "3.");
3446 }
3447
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf127235)3448 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf127235)
3449 {
3450 SwDoc* pDoc = createDoc("tdf127235.odt");
3451 // This resulted in a layout loop.
3452 pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
3453 }
3454
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testShapeAllowOverlap)3455 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testShapeAllowOverlap)
3456 {
3457 // Need to find out why this fails on macOS.
3458 #ifndef MACOSX
3459 // Create an empty document with two, intentionally overlapping shapes.
3460 // Set their AllowOverlap property to false.
3461 loadURL("private:factory/swriter", nullptr);
3462 uno::Reference<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
3463 awt::Point aPoint(1000, 1000);
3464 awt::Size aSize(2000, 2000);
3465 uno::Reference<drawing::XShape> xShape(
3466 xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
3467 xShape->setPosition(aPoint);
3468 xShape->setSize(aSize);
3469 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
3470 uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
3471 xShapeProperties->setPropertyValue("AllowOverlap", uno::makeAny(false));
3472 xShapeProperties->setPropertyValue("AnchorType",
3473 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
3474 xDrawPageSupplier->getDrawPage()->add(xShape);
3475
3476 aPoint = awt::Point(2000, 2000);
3477 xShape.set(xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
3478 xShape->setPosition(aPoint);
3479 xShape->setSize(aSize);
3480 xShapeProperties.set(xShape, uno::UNO_QUERY);
3481 xShapeProperties->setPropertyValue("AllowOverlap", uno::makeAny(false));
3482 xShapeProperties->setPropertyValue("AnchorType",
3483 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
3484 xDrawPageSupplier->getDrawPage()->add(xShape);
3485
3486 // Now verify that the rectangle of the anchored objects don't overlap.
3487 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
3488 CPPUNIT_ASSERT(pTextDoc);
3489 SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
3490 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
3491 SwFrame* pPageFrame = pLayout->GetLower();
3492 SwFrame* pBodyFrame = pPageFrame->GetLower();
3493 SwFrame* pTextFrame = pBodyFrame->GetLower();
3494 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
3495 SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs();
3496 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs.size());
3497 SwAnchoredObject* pFirst = rObjs[0];
3498 SwAnchoredObject* pSecond = rObjs[1];
3499 // Without the accompanying fix in place, this test would have failed: the layout dump was
3500 // <bounds left="1984" top="1984" width="1137" height="1137"/>
3501 // <bounds left="2551" top="2551" width="1137" height="1137"/>
3502 // so there was a clear vertical overlap. (Allow for 1px tolerance.)
3503 OString aMessage = "Unexpected overlap: first shape's bottom is "
3504 + OString::number(pFirst->GetObjRect().Bottom()) + ", second shape's top is "
3505 + OString::number(pSecond->GetObjRect().Top());
3506 CPPUNIT_ASSERT_MESSAGE(aMessage.getStr(),
3507 std::abs(pFirst->GetObjRect().Bottom() - pSecond->GetObjRect().Top())
3508 < 15);
3509 #endif
3510 }
3511
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testShapeAllowOverlapWrap)3512 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testShapeAllowOverlapWrap)
3513 {
3514 // Create an empty document with two, intentionally overlapping shapes.
3515 // Set their AllowOverlap property to false and their wrap to through.
3516 loadURL("private:factory/swriter", nullptr);
3517 uno::Reference<lang::XMultiServiceFactory> xDocument(mxComponent, uno::UNO_QUERY);
3518 awt::Point aPoint(1000, 1000);
3519 awt::Size aSize(2000, 2000);
3520 uno::Reference<drawing::XShape> xShape(
3521 xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
3522 xShape->setPosition(aPoint);
3523 xShape->setSize(aSize);
3524 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(xDocument, uno::UNO_QUERY);
3525 uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY);
3526 xShapeProperties->setPropertyValue("AllowOverlap", uno::makeAny(false));
3527 xShapeProperties->setPropertyValue("AnchorType",
3528 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
3529 xShapeProperties->setPropertyValue("Surround", uno::makeAny(text::WrapTextMode_THROUGH));
3530 xDrawPageSupplier->getDrawPage()->add(xShape);
3531
3532 aPoint = awt::Point(2000, 2000);
3533 xShape.set(xDocument->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
3534 xShape->setPosition(aPoint);
3535 xShape->setSize(aSize);
3536 xShapeProperties.set(xShape, uno::UNO_QUERY);
3537 xShapeProperties->setPropertyValue("AllowOverlap", uno::makeAny(false));
3538 xShapeProperties->setPropertyValue("AnchorType",
3539 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER));
3540 xShapeProperties->setPropertyValue("Surround", uno::makeAny(text::WrapTextMode_THROUGH));
3541 xDrawPageSupplier->getDrawPage()->add(xShape);
3542
3543 // Now verify that the rectangle of the anchored objects do overlap.
3544 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
3545 CPPUNIT_ASSERT(pTextDoc);
3546 SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc();
3547 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
3548 SwFrame* pPageFrame = pLayout->GetLower();
3549 SwFrame* pBodyFrame = pPageFrame->GetLower();
3550 SwFrame* pTextFrame = pBodyFrame->GetLower();
3551 CPPUNIT_ASSERT(pTextFrame->GetDrawObjs());
3552 SwSortedObjs& rObjs = *pTextFrame->GetDrawObjs();
3553 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs.size());
3554 SwAnchoredObject* pFirst = rObjs[0];
3555 SwAnchoredObject* pSecond = rObjs[1];
3556 // Without the accompanying fix in place, this test would have failed: AllowOverlap=no had
3557 // priority over Surround=through (which is bad for Word compat).
3558 CPPUNIT_ASSERT(pSecond->GetObjRect().IsOver(pFirst->GetObjRect()));
3559 }
3560
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf124600)3561 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf124600)
3562 {
3563 createDoc("tdf124600.docx");
3564 xmlDocPtr pXmlDoc = parseLayoutDump();
3565
3566 // Without the accompanying fix in place, this test would have failed with:
3567 // - Expected: 1
3568 // - Actual : 2
3569 // i.e. the last line in the body text had 2 lines, while it should have 1, as Word does (as the
3570 // fly frame does not intersect with the print area of the paragraph.)
3571 assertXPath(pXmlDoc, "/root/page/body/txt[2]/LineBreak", 1);
3572 }
3573
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf124601)3574 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf124601)
3575 {
3576 // This is a testcase for the ContinuousEndnotes compat flag.
3577 // The document has 2 pages, the endnote anchor is on the first page.
3578 // The endnote should be on the 2nd page together with the last page content.
3579 createDoc("tdf124601.doc");
3580 xmlDocPtr pXmlDoc = parseLayoutDump();
3581
3582 // Without the accompanying fix in place, this test would have failed with:
3583 // - Expected: 2
3584 // - Actual : 3
3585 // i.e. there was a separate endnote page, even when the ContinuousEndnotes compat option was
3586 // on.
3587 assertXPath(pXmlDoc, "/root/page", 2);
3588 assertXPath(pXmlDoc, "/root/page[2]/ftncont", 1);
3589 }
3590
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf124601b)3591 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf124601b)
3592 {
3593 // Table has an image, which is anchored in the first row, but its vertical position is large
3594 // enough to be rendered in the second row.
3595 // The shape has layoutInCell=1, so should match what Word does here.
3596 // Also the horizontal position should be in the last column, even if the anchor is in the
3597 // last-but-one column.
3598 createDoc("tdf124601b.doc");
3599 xmlDocPtr pXmlDoc = parseLayoutDump();
3600
3601 sal_Int32 nFlyTop = getXPath(pXmlDoc, "//fly/infos/bounds", "top").toInt32();
3602 sal_Int32 nFlyLeft = getXPath(pXmlDoc, "//fly/infos/bounds", "left").toInt32();
3603 sal_Int32 nFlyRight = nFlyLeft + getXPath(pXmlDoc, "//fly/infos/bounds", "width").toInt32();
3604 sal_Int32 nSecondRowTop = getXPath(pXmlDoc, "//tab/row[2]/infos/bounds", "top").toInt32();
3605 sal_Int32 nLastCellLeft
3606 = getXPath(pXmlDoc, "//tab/row[1]/cell[5]/infos/bounds", "left").toInt32();
3607 sal_Int32 nLastCellRight
3608 = nLastCellLeft + getXPath(pXmlDoc, "//tab/row[1]/cell[5]/infos/bounds", "width").toInt32();
3609 // Without the accompanying fix in place, this test would have failed with:
3610 // - Expected greater than: 3736
3611 // - Actual : 2852
3612 // i.e. the image was still inside the first row.
3613 CPPUNIT_ASSERT_GREATER(nSecondRowTop, nFlyTop);
3614
3615 // Without the accompanying fix in place, this test would have failed with:
3616 // - Expected greater than: 9640
3617 // - Actual : 9639
3618 // i.e. the right edge of the image was not within the bounds of the last column, the right edge
3619 // was in the last-but-one column.
3620 CPPUNIT_ASSERT_GREATER(nLastCellLeft, nFlyRight);
3621 CPPUNIT_ASSERT_LESS(nLastCellRight, nFlyRight);
3622 }
3623
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf124770)3624 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf124770)
3625 {
3626 // Enable content over margin.
3627 SwDoc* pDoc = createDoc();
3628 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN, true);
3629
3630 // Set page width.
3631 SwPageDesc& rPageDesc = pDoc->GetPageDesc(0);
3632 SwFrameFormat& rPageFormat = rPageDesc.GetMaster();
3633 const SwAttrSet& rPageSet = rPageFormat.GetAttrSet();
3634 SwFormatFrameSize aPageSize = rPageSet.GetFrameSize();
3635 aPageSize.SetWidth(3703);
3636 rPageFormat.SetFormatAttr(aPageSize);
3637
3638 // Set left and right margin.
3639 SvxLRSpaceItem aLRSpace = rPageSet.GetLRSpace();
3640 aLRSpace.SetLeft(1418);
3641 aLRSpace.SetRight(1418);
3642 rPageFormat.SetFormatAttr(aLRSpace);
3643 pDoc->ChgPageDesc(0, rPageDesc);
3644
3645 // Set font to italic 20pt Liberation Serif.
3646 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3647 SfxItemSet aTextSet(pWrtShell->GetView().GetPool(),
3648 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END - 1>{});
3649 SvxFontItem aFont(RES_CHRATR_FONT);
3650 aFont.SetFamilyName("Liberation Serif");
3651 aTextSet.Put(aFont);
3652 SvxFontHeightItem aHeight(400, 100, RES_CHRATR_FONTSIZE);
3653 aTextSet.Put(aHeight);
3654 SvxPostureItem aItalic(ITALIC_NORMAL, RES_CHRATR_POSTURE);
3655 aTextSet.Put(aItalic);
3656 pWrtShell->SetAttrSet(aTextSet);
3657
3658 // Insert the text.
3659 pWrtShell->Insert2("HHH");
3660
3661 xmlDocPtr pXmlDoc = parseLayoutDump();
3662 // Without the accompanying fix in place, this test would have failed with:
3663 // - Expected: 1
3664 // - Actual : 2
3665 // i.e. the italic string was broken into 2 lines, while Word kept it in a single line.
3666 assertXPath(pXmlDoc, "/root/page/body/txt[1]/LineBreak", 1);
3667 }
3668
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testContinuousEndnotesInsertPageAtStart)3669 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testContinuousEndnotesInsertPageAtStart)
3670 {
3671 // Create a new document with CONTINUOUS_ENDNOTES enabled.
3672 SwDoc* pDoc = createDoc();
3673 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
3674
3675 // Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on
3676 // the 2nd page).
3677 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3678 pWrtShell->InsertPageBreak();
3679 pWrtShell->InsertFootnote("endnote", /*bEndNote=*/true, /*bEdit=*/false);
3680
3681 // Add a new page at the start of the document.
3682 pWrtShell->SttEndDoc(/*bStart=*/true);
3683 pWrtShell->InsertPageBreak();
3684
3685 // Make sure that the endnote is moved from the 2nd page to the 3rd one.
3686 xmlDocPtr pXmlDoc = parseLayoutDump();
3687 assertXPath(pXmlDoc, "/root/page", 3);
3688 // Without the accompanying fix in place, this test would have failed with:
3689 // - Expected: 1
3690 // - Actual : 0
3691 // i.e. the footnote container remained on page 2.
3692 assertXPath(pXmlDoc, "/root/page[3]/ftncont", 1);
3693 }
3694
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testContinuousEndnotesDeletePageAtStart)3695 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testContinuousEndnotesDeletePageAtStart)
3696 {
3697 // Create a new document with CONTINUOUS_ENDNOTES enabled.
3698 SwDoc* pDoc = createDoc();
3699 pDoc->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES, true);
3700
3701 // Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on
3702 // the 2nd page).
3703 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3704 pWrtShell->InsertPageBreak();
3705 pWrtShell->InsertFootnote("endnote", /*bEndNote=*/true, /*bEdit=*/false);
3706
3707 // Remove the empty page at the start of the document.
3708 pWrtShell->SttEndDoc(/*bStart=*/true);
3709 pWrtShell->DelRight();
3710
3711 // Make sure that the endnote is moved from the 2nd page to the 1st one.
3712 xmlDocPtr pXmlDoc = parseLayoutDump();
3713 // Without the accompanying fix in place, this test would have failed with:
3714 // - Expected: 1
3715 // - Actual : 2
3716 // i.e. the endnote remained on an (otherwise) empty 2nd page.
3717 assertXPath(pXmlDoc, "/root/page", 1);
3718 assertXPath(pXmlDoc, "/root/page[1]/ftncont", 1);
3719 }
3720
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf128399)3721 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf128399)
3722 {
3723 SwDoc* pDoc = createDoc("tdf128399.docx");
3724 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
3725 SwFrame* pPage = pLayout->GetLower();
3726 SwFrame* pBody = pPage->GetLower();
3727 SwFrame* pTable = pBody->GetLower();
3728 SwFrame* pRow1 = pTable->GetLower();
3729 SwFrame* pRow2 = pRow1->GetNext();
3730 const SwRect& rRow2Rect = pRow2->getFrameArea();
3731 Point aPoint = rRow2Rect.Center();
3732
3733 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3734 SwPosition aPosition = *pWrtShell->GetCursor()->Start();
3735 SwPosition aFirstRow(aPosition);
3736 SwCursorMoveState aState(MV_NONE);
3737 pLayout->GetCursorOfst(&aPosition, aPoint, &aState);
3738 // Second row is +3: end node, start node and the first text node in the 2nd row.
3739 sal_uLong nExpected = aFirstRow.nNode.GetIndex() + 3;
3740
3741 // Without the accompanying fix in place, this test would have failed with:
3742 // - Expected: 14
3743 // - Actual : 11
3744 // i.e. clicking on the center of the 2nd row placed the cursor in the 1st row.
3745 CPPUNIT_ASSERT_EQUAL(nExpected, aPosition.nNode.GetIndex());
3746 }
3747
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf105481)3748 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf105481)
3749 {
3750 createDoc("tdf105481.odt");
3751 xmlDocPtr pXmlDoc = parseLayoutDump();
3752 CPPUNIT_ASSERT(pXmlDoc);
3753
3754 // Without the accompanying fix in place, this test would have failed
3755 // because the vertical position of the as-char shape object and the
3756 // as-char math object will be wrong (below/beyond the text frame's bottom).
3757
3758 SwTwips nTxtTop = getXPath(pXmlDoc,
3759 "/root/page/anchored/fly/txt[2]"
3760 "/infos/bounds",
3761 "top")
3762 .toInt32();
3763 SwTwips nTxtBottom = nTxtTop
3764 + getXPath(pXmlDoc,
3765 "/root/page/anchored/fly/txt[2]"
3766 "/infos/bounds",
3767 "height")
3768 .toInt32();
3769
3770 SwTwips nFormula1Top = getXPath(pXmlDoc,
3771 "/root/page/anchored/fly/txt[2]"
3772 "/anchored/fly[1]/infos/bounds",
3773 "top")
3774 .toInt32();
3775 SwTwips nFormula1Bottom = nFormula1Top
3776 + getXPath(pXmlDoc,
3777 "/root/page/anchored/fly/txt[2]"
3778 "/anchored/fly[1]/infos/bounds",
3779 "height")
3780 .toInt32();
3781
3782 SwTwips nFormula2Top = getXPath(pXmlDoc,
3783 "/root/page/anchored/fly/txt[2]"
3784 "/anchored/fly[2]/infos/bounds",
3785 "top")
3786 .toInt32();
3787 SwTwips nFormula2Bottom = nFormula2Top
3788 + getXPath(pXmlDoc,
3789 "/root/page/anchored/fly/txt[2]"
3790 "/anchored/fly[2]/infos/bounds",
3791 "height")
3792 .toInt32();
3793
3794 // Ensure that the two formula positions are at least between top and bottom of the text frame.
3795 // The below two are satisfied even without the fix.
3796 CPPUNIT_ASSERT_GREATEREQUAL(nTxtTop, nFormula1Top);
3797 CPPUNIT_ASSERT_GREATEREQUAL(nTxtTop, nFormula2Top);
3798
3799 // Without the accompanying fix in place, this test would have failed with:
3800 // - Expected less than or equal to : 14423
3801 // - Actual : 14828
3802 // that is, the formula is below the text-frame's y bound.
3803 CPPUNIT_ASSERT_LESSEQUAL(nTxtBottom, nFormula1Bottom);
3804 // Similarly for formula # 2 :
3805 // - Expected less than or equal to : 14423
3806 // - Actual : 15035
3807 // that is, the formula is below the text-frame's y bound.
3808 CPPUNIT_ASSERT_LESSEQUAL(nTxtBottom, nFormula2Bottom);
3809 }
3810
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf121658)3811 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf121658)
3812 {
3813 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
3814 if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
3815 return;
3816
3817 createDoc("tdf121658.odt");
3818 xmlDocPtr pXmlDoc = parseLayoutDump();
3819
3820 // Only 2 hyphenated words should appear in the document (in the lowercase words).
3821 // Uppercase words should not be hyphenated.
3822 assertXPath(pXmlDoc, "//Special[@nType='PortionType::Hyphen']", 2);
3823 }
3824
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf117982)3825 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf117982)
3826 {
3827 SwDoc* pDocument = createDoc("tdf117982.docx");
3828 SwDocShell* pShell = pDocument->GetDocShell();
3829 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
3830 MetafileXmlDump dumper;
3831 xmlDocPtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
3832 assertXPathContent(pXmlDoc, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "FOO AAA");
3833 //The first cell must be "FOO AAA". If not, this means the first cell content not visible in
3834 //the source document.
3835 }
3836
lcl_getVisibleFlyObjRect(SwWrtShell * pWrtShell)3837 static SwRect lcl_getVisibleFlyObjRect(SwWrtShell* pWrtShell)
3838 {
3839 SwRootFrame* pRoot = pWrtShell->GetLayout();
3840 SwPageFrame* pPage = static_cast<SwPageFrame*>(pRoot->GetLower());
3841 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
3842 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
3843 SwSortedObjs* pDrawObjs = pPage->GetDrawObjs();
3844 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDrawObjs->size());
3845 SwAnchoredObject* pDrawObj = (*pDrawObjs)[0];
3846 CPPUNIT_ASSERT_EQUAL(OUString("Rahmen8"), pDrawObj->GetFrameFormat().GetName());
3847 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
3848 pDrawObjs = pPage->GetDrawObjs();
3849 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDrawObjs->size());
3850 pDrawObj = (*pDrawObjs)[0];
3851 CPPUNIT_ASSERT_EQUAL(OUString("Rahmen123"), pDrawObj->GetFrameFormat().GetName());
3852 SwRect aFlyRect = pDrawObj->GetObjRect();
3853 CPPUNIT_ASSERT(pPage->getFrameArea().IsInside(aFlyRect));
3854 return aFlyRect;
3855 }
3856
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testStableAtPageAnchoredFlyPosition)3857 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testStableAtPageAnchoredFlyPosition)
3858 {
3859 // this doc has two page-anchored frames: one tiny on page 3 and one large on page 4.
3860 // it also has a style:master-page named "StandardEntwurf", which contains some fields.
3861 // if you add a break to page 2, or append some text to page 4 (or just toggle display field names),
3862 // the page anchored frame on page 4 vanishes, as it is incorrectly moved out of the page bounds.
3863 SwDoc* pDoc = createDoc("stable-at-page-anchored-fly-position.odt");
3864 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3865
3866 // look up the layout position of the page-bound frame on page four
3867 SwRect aOrigRect = lcl_getVisibleFlyObjRect(pWrtShell);
3868
3869 // append some text to the document to trigger bug / relayout
3870 pWrtShell->SttEndDoc(false);
3871 pWrtShell->Insert("foo");
3872
3873 // get the current position of the frame on page four
3874 SwRect aRelayoutRect = lcl_getVisibleFlyObjRect(pWrtShell);
3875
3876 // the anchored frame should not have moved
3877 CPPUNIT_ASSERT_EQUAL(aOrigRect, aRelayoutRect);
3878 }
3879
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testBtlrTableRowSpan)3880 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testBtlrTableRowSpan)
3881 {
3882 // Load a document which has a table. The A1 cell has btlr text direction, and the A1..A3 cells
3883 // are merged.
3884 load(DATA_DIRECTORY, "btlr-table-row-span.odt");
3885 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
3886 SwDocShell* pShell = pTextDoc->GetDocShell();
3887 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
3888 MetafileXmlDump aDumper;
3889 xmlDocPtr pXmlDoc = dumpAndParse(aDumper, *xMetaFile);
3890
3891 // Without the accompanying fix in place, this test would have failed with:
3892 // - Expected: USA
3893 // - Actual : West
3894 // i.e. the "USA" text completely disappeared.
3895 assertXPathContent(pXmlDoc, "//textarray[1]/text", "USA");
3896 }
3897
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testContinuousEndnotesMoveBackwards)3898 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testContinuousEndnotesMoveBackwards)
3899 {
3900 // Load a document with the ContinuousEndnotes flag turned on.
3901 load(DATA_DIRECTORY, "continuous-endnotes-move-backwards.doc");
3902 xmlDocPtr pLayout = parseLayoutDump();
3903 // We have 2 pages.
3904 assertXPath(pLayout, "/root/page", 2);
3905 // No endnote container on page 1.
3906 // Without the accompanying fix in place, this test would have failed with:
3907 // - Expected: 0
3908 // - Actual : 1
3909 // i.e. there were unexpected endnotes on page 1.
3910 assertXPath(pLayout, "/root/page[1]/ftncont", 0);
3911 // All endnotes are in a container on page 2.
3912 assertXPath(pLayout, "/root/page[2]/ftncont", 1);
3913 }
3914
CPPUNIT_TEST_FIXTURE(SwLayoutWriter,testTdf134548)3915 CPPUNIT_TEST_FIXTURE(SwLayoutWriter, testTdf134548)
3916 {
3917 createDoc("tdf134548.odt");
3918
3919 // Second paragraph has two non zero width tabs in beginning of line
3920 {
3921 OUString sNodeType = parseDump("/root/page/body/txt[2]/Text[1]", "nType");
3922 CPPUNIT_ASSERT_EQUAL(OUString("PortionType::TabLeft"), sNodeType);
3923 sal_Int32 nWidth = parseDump("/root/page/body/txt[2]/Text[1]", "nWidth").toInt32();
3924 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth);
3925 }
3926 {
3927 OUString sNodeType = parseDump("/root/page/body/txt[2]/Text[2]", "nType");
3928 CPPUNIT_ASSERT_EQUAL(OUString("PortionType::TabLeft"), sNodeType);
3929 sal_Int32 nWidth = parseDump("/root/page/body/txt[2]/Text[2]", "nWidth").toInt32();
3930 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth);
3931 }
3932 }
3933
3934 CPPUNIT_PLUGIN_IMPLEMENT();
3935
3936 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
3937