1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <swmodeltestbase.hxx>
11 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
12 #include <comphelper/propertysequence.hxx>
13 #include <com/sun/star/linguistic2/XHyphenator.hpp>
14 #include <com/sun/star/text/WrapTextMode.hpp>
15 #include <comphelper/scopeguard.hxx>
16 #include <vcl/event.hxx>
17 #include <vcl/scheduler.hxx>
18 #include <editeng/lrspitem.hxx>
19 #include <editeng/fontitem.hxx>
20 #include <editeng/fhgtitem.hxx>
21 #include <editeng/postitem.hxx>
22 #include <editeng/unolingu.hxx>
23 #include <editeng/outlobj.hxx>
24 #include <editeng/editobj.hxx>
25 #include <comphelper/sequence.hxx>
27 #include <fmtanchr.hxx>
28 #include <fmtfsize.hxx>
29 #include <fmtcntnt.hxx>
34 #include <pagefrm.hxx>
35 #include <bodyfrm.hxx>
36 #include <sortedobjs.hxx>
37 #include <anchoredobject.hxx>
40 #include <IDocumentSettingAccess.hxx>
41 #include <unotxdoc.hxx>
42 #include <rootfrm.hxx>
44 #include <IDocumentLayoutAccess.hxx>
45 #include <IDocumentDrawModelAccess.hxx>
46 #include <IDocumentRedlineAccess.hxx>
47 #include <textboxhelper.hxx>
48 #include <unoframe.hxx>
49 #include <drawdoc.hxx>
50 #include <svx/svdpage.hxx>
51 #include <svx/svdotext.hxx>
52 #include <dcontact.hxx>
54 constexpr OUStringLiteral DATA_DIRECTORY
= u
"/sw/qa/extras/layout/data/";
56 /// Test to assert layout / rendering result of Writer.
57 class SwLayoutWriter
: public SwModelTestBase
60 void CheckRedlineFootnotesHidden();
61 void CheckRedlineSectionsHidden();
64 // this is a member because our test classes have protected members :(
65 void SwLayoutWriter::CheckRedlineFootnotesHidden()
67 discardDumpedLayout();
68 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
69 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "24");
70 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "nType", "PortionType::Footnote");
71 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
72 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
73 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
74 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[2]", "nType", "PortionType::Footnote");
75 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
76 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex", "13");
77 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
78 "PortionType::FootnoteNum");
79 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
80 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "nType",
82 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "Portion", "ac");
83 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/merged", "paraPropsNodeIndex", "16");
84 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
85 "PortionType::FootnoteNum");
86 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
87 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
89 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "mo");
92 void SwLayoutWriter::CheckRedlineSectionsHidden()
94 discardDumpedLayout();
95 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
96 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "12");
97 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
98 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "folah");
99 assertXPath(pXmlDoc
, "/root/page[1]/body/section[1]/txt[1]/merged", "paraPropsNodeIndex", "20");
100 assertXPath(pXmlDoc
, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "nType",
101 "PortionType::Para");
102 assertXPath(pXmlDoc
, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "Portion", "folah");
105 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testRedlineFootnotes
)
107 createSwDoc(DATA_DIRECTORY
, "redline_footnotes.odt");
108 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
109 CPPUNIT_ASSERT(pTextDoc
);
110 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
111 SwRootFrame
* pLayout(pDoc
->getIDocumentLayoutAccess().GetCurrentLayout());
112 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
115 CheckRedlineFootnotesHidden();
117 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
118 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
119 discardDumpedLayout();
120 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
122 // show: nothing is merged
123 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
124 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
125 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
126 xmlXPathFreeObject(pXmlObj
);
127 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "nType", "PortionType::Footnote");
128 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
129 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
130 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
131 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
132 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
133 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[2]", "nType", "PortionType::Footnote");
134 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
136 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
137 "PortionType::FootnoteNum");
138 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
139 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "nType",
140 "PortionType::Text");
141 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[1]", "Portion", "a");
142 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[2]", "nType",
143 "PortionType::Text");
144 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[2]", "Portion", "b");
145 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[3]", "nType",
146 "PortionType::Text");
147 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Text[3]", "Portion", "c");
148 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
149 "PortionType::FootnoteNum");
150 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
151 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
152 "PortionType::Text");
153 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "def");
154 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Text");
155 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "b");
156 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Special[1]", "nType", "PortionType::Footnote");
157 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Special[1]", "rText", "3");
158 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[2]", "nType", "PortionType::Text");
159 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[2]", "Portion", "ar");
160 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[3]/txt[1]/Special[1]", "nType",
161 "PortionType::FootnoteNum");
162 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[3]/txt[1]/Special[1]", "rText", "3");
163 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[3]/txt[1]/Text[1]", "nType",
164 "PortionType::Text");
165 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[3]/txt[1]/Text[1]", "Portion", "ghi");
166 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Special[1]", "nType", "PortionType::Footnote");
167 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Special[1]", "rText", "4");
168 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
169 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
170 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
171 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
172 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Special[2]", "nType", "PortionType::Footnote");
173 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Special[2]", "rText", "5");
175 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[4]/txt[1]/Special[1]", "nType",
176 "PortionType::FootnoteNum");
177 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[4]/txt[1]/Special[1]", "rText", "4");
178 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[4]/txt[1]/Text[1]", "nType",
179 "PortionType::Text");
180 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[4]/txt[1]/Text[1]", "Portion", "jkl");
181 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[5]/txt[1]/Special[1]", "nType",
182 "PortionType::FootnoteNum");
183 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[5]/txt[1]/Special[1]", "rText", "5");
184 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[1]", "nType",
185 "PortionType::Text");
186 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[1]", "Portion", "m");
187 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[2]", "nType",
188 "PortionType::Text");
189 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[2]", "Portion", "n");
190 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[3]", "nType",
191 "PortionType::Text");
192 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[5]/txt[1]/Text[3]", "Portion", "o");
195 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
196 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
197 discardDumpedLayout();
198 CheckRedlineFootnotesHidden();
201 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, TestTdf136588
)
203 load(DATA_DIRECTORY
, "tdf136588.docx");
204 auto pXMLLayoutDump
= parseLayoutDump();
205 CPPUNIT_ASSERT(pXMLLayoutDump
);
207 //there was a bad line break before, the correct break layout is this:
208 assertXPath(pXMLLayoutDump
, "/root/page/body/txt[2]/LineBreak[2]", "Line",
209 "effectively by modern-day small to ");
212 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testRedlineFlysInBody
)
214 loadURL("private:factory/swriter", nullptr);
215 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
216 CPPUNIT_ASSERT(pTextDoc
);
217 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
218 SwWrtShell
* pWrtShell
= pTextDoc
->GetDocShell()->GetWrtShell();
219 SwRootFrame
* pLayout(pWrtShell
->GetLayout());
220 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
221 pWrtShell
->Insert("foo");
222 pWrtShell
->SplitNode(false);
223 pWrtShell
->Insert("bar");
224 pWrtShell
->SplitNode(false);
225 pWrtShell
->Insert("baz");
226 SfxItemSet
flySet(pDoc
->GetAttrPool(),
227 svl::Items
<RES_FRM_SIZE
, RES_FRM_SIZE
, RES_ANCHOR
, RES_ANCHOR
>);
228 SwFormatAnchor
anchor(RndStdIds::FLY_AT_CHAR
);
229 pWrtShell
->StartOfSection(false);
230 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 1, /*bBasicCall=*/false);
231 anchor
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
233 SwFormatFrameSize
size(SwFrameSize::Minimum
, 1000, 1000);
234 flySet
.Put(size
); // set a size, else we get 1 char per line...
235 SwFrameFormat
const* pFly
= pWrtShell
->NewFlyFrame(flySet
, /*bAnchValid=*/true);
236 CPPUNIT_ASSERT(pFly
!= nullptr);
238 pWrtShell
->GotoFly(pFly
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
239 pWrtShell
->Insert("abc");
240 pWrtShell
->SplitNode(false);
241 pWrtShell
->Insert("def");
242 pWrtShell
->SplitNode(false);
243 pWrtShell
->Insert("ghi");
245 dispatchCommand(mxComponent
, ".uno:TrackChanges", {});
246 // delete redline inside fly
247 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
248 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/true, 8, /*bBasicCall=*/false);
251 pWrtShell
->SttEndDoc(true); // note: SttDoc actually moves to start of fly?
252 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
253 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/true, 7, /*bBasicCall=*/false);
256 for (int i
= 0; i
< 2; ++i
)
258 if (i
== 1) // secondly, try with different anchor type
260 anchor
.SetType(RndStdIds::FLY_AT_PARA
);
261 SwPosition
pos(*anchor
.GetContentAnchor());
262 pos
.nContent
.Assign(nullptr, 0);
263 anchor
.SetAnchor(&pos
);
264 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
267 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
268 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
269 discardDumpedLayout();
270 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
271 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
272 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
273 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
274 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
275 "paraPropsNodeIndex", "6");
276 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
277 "PortionType::Para");
278 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
281 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
282 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
283 discardDumpedLayout();
284 pXmlDoc
= parseLayoutDump();
286 { // show: nothing is merged
287 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
288 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
289 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
290 xmlXPathFreeObject(pXmlObj
);
293 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
294 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
295 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
296 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
297 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
298 "PortionType::Text");
299 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
301 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
302 "PortionType::Text");
303 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
305 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
306 "PortionType::Para");
307 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
309 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
310 "PortionType::Text");
311 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
313 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
314 "PortionType::Text");
315 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
317 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
318 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
319 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
320 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
321 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
322 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
325 // anchor to 2nd (deleted) paragraph
326 pWrtShell
->StartOfSection();
327 pWrtShell
->Down(false, 1);
328 anchor
.SetType(RndStdIds::FLY_AT_CHAR
);
329 anchor
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
330 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
332 for (int i
= 0; i
< 2; ++i
)
334 if (i
== 1) // secondly, try with different anchor type
336 anchor
.SetType(RndStdIds::FLY_AT_PARA
);
337 SwPosition
pos(*anchor
.GetContentAnchor());
338 pos
.nContent
.Assign(nullptr, 0);
339 anchor
.SetAnchor(&pos
);
340 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
343 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
344 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
345 discardDumpedLayout();
346 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
347 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
348 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
349 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
351 { // hide: no anchored object shown
352 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//anchored");
353 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
354 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
355 xmlXPathFreeObject(pXmlObj
);
358 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
359 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
360 discardDumpedLayout();
361 pXmlDoc
= parseLayoutDump();
363 { // show: nothing is merged
364 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
365 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
366 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
367 xmlXPathFreeObject(pXmlObj
);
370 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
371 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
372 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
373 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
374 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
375 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
376 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
377 "PortionType::Text");
378 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
380 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
381 "PortionType::Text");
382 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
384 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
385 "PortionType::Para");
386 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
388 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
389 "PortionType::Text");
390 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
392 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
393 "PortionType::Text");
394 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
396 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
397 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
398 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
399 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
402 // anchor to 3rd paragraph
403 pWrtShell
->EndOfSection();
404 anchor
.SetType(RndStdIds::FLY_AT_CHAR
);
405 anchor
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
406 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
408 for (int i
= 0; i
< 2; ++i
)
410 if (i
== 1) // secondly, try with different anchor type
412 anchor
.SetType(RndStdIds::FLY_AT_PARA
);
413 SwPosition
pos(*anchor
.GetContentAnchor());
414 pos
.nContent
.Assign(nullptr, 0);
415 anchor
.SetAnchor(&pos
);
416 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
419 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
420 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
421 discardDumpedLayout();
422 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
423 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "14");
424 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
425 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
426 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
427 "paraPropsNodeIndex", "6");
428 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
429 "PortionType::Para");
430 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
433 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
434 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
435 discardDumpedLayout();
436 pXmlDoc
= parseLayoutDump();
438 { // show: nothing is merged
439 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
440 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
441 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
442 xmlXPathFreeObject(pXmlObj
);
445 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
446 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
447 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
448 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
449 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
450 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
451 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
452 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
453 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
454 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
455 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
456 "PortionType::Text");
457 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
459 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
460 "PortionType::Text");
461 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
463 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
464 "PortionType::Para");
465 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
467 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
468 "PortionType::Text");
469 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
471 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
472 "PortionType::Text");
473 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
478 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, TestTdf134272
)
480 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf134472.odt");
481 CPPUNIT_ASSERT(pDoc
);
482 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
483 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/infos/bounds", "height", "843");
484 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/infos/bounds", "bottom", "2819");
487 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, TestNestedTableMoveFwd
)
489 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tabellen_test_windows_1.odt");
490 CPPUNIT_ASSERT(pDoc
);
491 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
492 // the row with the nested table should not be split but be the first row on page 2
493 assertXPath(pXmlDoc
, "/root/page[1]/body/tab[1]/row[last()]/cell[1]/txt[1]/Text", "Portion",
495 assertXPath(pXmlDoc
, "/root/page[2]/body/tab[1]/row[1]/cell[1]/tab[1]/row[1]/cell[1]/txt/Text",
496 "Portion", "Tabelle 2");
499 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, TestTdf136613
)
501 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf136613.docx");
502 CPPUNIT_ASSERT(pDoc
);
504 //get the flys and the root frame
505 const auto vFlyFormats
= pDoc
->GetFlyFrameFormats(FLYCNTTYPE_ALL
, true);
506 const auto vFrames
= pDoc
->GetAllLayouts();
508 CPPUNIT_ASSERT(!vFrames
.empty());
509 CPPUNIT_ASSERT(!vFlyFormats
.empty());
511 //get the page frame from the root
512 SwFrame
* pPageFrame
= vFrames
[0]->Lower();
513 CPPUNIT_ASSERT(pPageFrame
);
515 //get the rectangle of the page
516 const SwRect
& rPageRect
= pPageFrame
->getFrameArea();
518 //check the flys and...
519 for (auto pFlyFormat
: vFlyFormats
)
521 //...the rectangle of the fly location...
522 const SwRect
& rRect
= pFlyFormat
->FindLayoutRect();
523 CPPUNIT_ASSERT(!rRect
.IsEmpty());
525 //...if it is on the page. This will fail if not.
526 CPPUNIT_ASSERT_MESSAGE("The pictures are outside the page!", rPageRect
.Contains(rRect
));
530 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf88496
)
532 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf88496.docx");
533 CPPUNIT_ASSERT(pDoc
);
534 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
535 // This was 4, table fallback "switch off repeating header" started on a new page
536 assertXPath(pXmlDoc
, "/root/page", 3);
539 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testRedlineFlysInHeader
)
541 loadURL("private:factory/swriter", nullptr);
542 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
543 CPPUNIT_ASSERT(pTextDoc
);
544 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
545 SwWrtShell
* pWrtShell
= pTextDoc
->GetDocShell()->GetWrtShell();
546 SwRootFrame
* pLayout(pWrtShell
->GetLayout());
547 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
548 pWrtShell
->ChangeHeaderOrFooter(u
"Default Page Style", /*bHeader*/ true, /*bOn*/ true, false);
551 ->IsInHeaderFooter()); // assume this is supposed to put cursor in the new header...
552 pWrtShell
->Insert("foo");
553 pWrtShell
->SplitNode(false);
554 pWrtShell
->Insert("bar");
555 pWrtShell
->SplitNode(false);
556 pWrtShell
->Insert("baz");
557 SfxItemSet
flySet(pDoc
->GetAttrPool(),
558 svl::Items
<RES_FRM_SIZE
, RES_FRM_SIZE
, RES_ANCHOR
, RES_ANCHOR
>);
559 SwFormatAnchor
anchor(RndStdIds::FLY_AT_CHAR
);
560 pWrtShell
->StartOfSection(false);
561 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 1, /*bBasicCall=*/false);
562 anchor
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
564 SwFormatFrameSize
size(SwFrameSize::Minimum
, 1000, 1000);
565 flySet
.Put(size
); // set a size, else we get 1 char per line...
566 SwFrameFormat
const* pFly
= pWrtShell
->NewFlyFrame(flySet
, /*bAnchValid=*/true);
567 CPPUNIT_ASSERT(pFly
!= nullptr);
569 pWrtShell
->GotoFly(pFly
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
570 pWrtShell
->Insert("abc");
571 pWrtShell
->SplitNode(false);
572 pWrtShell
->Insert("def");
573 pWrtShell
->SplitNode(false);
574 pWrtShell
->Insert("ghi");
576 dispatchCommand(mxComponent
, ".uno:TrackChanges", {});
577 // delete redline inside fly
578 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
579 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/true, 8, /*bBasicCall=*/false);
582 pWrtShell
->GotoHeaderText();
583 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
584 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/true, 7, /*bBasicCall=*/false);
587 for (int i
= 0; i
< 2; ++i
)
589 if (i
== 1) // secondly, try with different anchor type
591 anchor
.SetType(RndStdIds::FLY_AT_PARA
);
592 SwPosition
pos(*anchor
.GetContentAnchor());
593 pos
.nContent
.Assign(nullptr, 0);
594 anchor
.SetAnchor(&pos
);
595 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
598 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
599 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
600 discardDumpedLayout();
601 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
602 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
603 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
604 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
605 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Para");
606 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
607 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/merged",
608 "paraPropsNodeIndex", "11");
609 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
610 "PortionType::Para");
611 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
614 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
615 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
616 discardDumpedLayout();
617 pXmlDoc
= parseLayoutDump();
619 { // show: nothing is merged
620 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
621 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
622 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
623 xmlXPathFreeObject(pXmlObj
);
626 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
627 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
628 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Text");
629 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
630 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[2]", "nType", "PortionType::Text");
631 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
632 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
633 "PortionType::Text");
634 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
636 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
637 "PortionType::Text");
638 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
640 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
641 "PortionType::Para");
642 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
644 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
645 "PortionType::Text");
646 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
648 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
649 "PortionType::Text");
650 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
652 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/Text[1]", "nType", "PortionType::Para");
653 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
654 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[1]", "nType", "PortionType::Text");
655 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
656 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[2]", "nType", "PortionType::Text");
657 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
660 // anchor to 2nd (deleted) paragraph
661 pWrtShell
->StartOfSection();
662 pWrtShell
->Down(false, 1);
663 anchor
.SetType(RndStdIds::FLY_AT_CHAR
);
664 anchor
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
665 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
667 for (int i
= 0; i
< 2; ++i
)
669 if (i
== 1) // secondly, try with different anchor type
671 anchor
.SetType(RndStdIds::FLY_AT_PARA
);
672 SwPosition
pos(*anchor
.GetContentAnchor());
673 pos
.nContent
.Assign(nullptr, 0);
674 anchor
.SetAnchor(&pos
);
675 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
678 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
679 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
680 discardDumpedLayout();
681 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
682 // now the frame has no Text portion? not sure why it's a 0-length one first and now none?
683 // assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
684 // assertXPath(pXmlDoc, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
685 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
686 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Para");
687 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
689 { // hide: no anchored object shown
690 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//anchored");
691 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
692 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
693 xmlXPathFreeObject(pXmlObj
);
696 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
697 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
698 discardDumpedLayout();
699 pXmlDoc
= parseLayoutDump();
701 { // show: nothing is merged
702 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
703 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
704 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
705 xmlXPathFreeObject(pXmlObj
);
708 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
709 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
710 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Text");
711 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
712 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[2]", "nType", "PortionType::Text");
713 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
714 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/Text[1]", "nType", "PortionType::Para");
715 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
716 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
717 "PortionType::Text");
718 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
720 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
721 "PortionType::Text");
722 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
724 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
725 "PortionType::Para");
726 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
728 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
729 "PortionType::Text");
730 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
732 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
733 "PortionType::Text");
734 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
736 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[1]", "nType", "PortionType::Text");
737 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
738 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[2]", "nType", "PortionType::Text");
739 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
742 // anchor to 3rd paragraph
743 pWrtShell
->EndOfSection();
744 anchor
.SetType(RndStdIds::FLY_AT_CHAR
);
745 anchor
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
746 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
748 for (int i
= 0; i
< 2; ++i
)
750 if (i
== 1) // secondly, try with different anchor type
752 anchor
.SetType(RndStdIds::FLY_AT_PARA
);
753 SwPosition
pos(*anchor
.GetContentAnchor());
754 pos
.nContent
.Assign(nullptr, 0);
755 anchor
.SetAnchor(&pos
);
756 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
759 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
760 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
761 discardDumpedLayout();
762 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
763 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
764 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
765 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/merged", "paraPropsNodeIndex", "6");
766 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Para");
767 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "foaz");
768 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/merged",
769 "paraPropsNodeIndex", "11");
770 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
771 "PortionType::Para");
772 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
775 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
776 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
777 discardDumpedLayout();
778 pXmlDoc
= parseLayoutDump();
780 { // show: nothing is merged
781 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
782 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
783 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
784 xmlXPathFreeObject(pXmlObj
);
787 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
788 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nLength", "0");
789 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "nType", "PortionType::Text");
790 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[1]", "Portion", "fo");
791 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[2]", "nType", "PortionType::Text");
792 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[1]/Text[2]", "Portion", "o");
793 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/Text[1]", "nType", "PortionType::Para");
794 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[2]/Text[1]", "Portion", "bar");
795 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[1]", "nType", "PortionType::Text");
796 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[1]", "Portion", "b");
797 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[2]", "nType", "PortionType::Text");
798 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/Text[2]", "Portion", "az");
799 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
800 "PortionType::Text");
801 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
803 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
804 "PortionType::Text");
805 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
807 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
808 "PortionType::Para");
809 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
811 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
812 "PortionType::Text");
813 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
815 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
816 "PortionType::Text");
817 assertXPath(pXmlDoc
, "/root/page[1]/header/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
822 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, TestTdf137025
)
824 // Check the padding of the textbox
825 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf137025.docx");
826 CPPUNIT_ASSERT(pDoc
);
827 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
828 CPPUNIT_ASSERT(pXmlDoc
);
830 // Check the layout xml
831 // SDRATTR_TEXT_LEFTDIST
833 "/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObject"
834 "/DefaultProperties/SfxItemSet/SdrMetricItem/SfxInt32Item[@whichId='1071']",
836 // SDRATTR_TEXT_RIGHTDIST
838 "/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObject"
839 "/DefaultProperties/SfxItemSet/SdrMetricItem/SfxInt32Item[@whichId='1072']",
841 // SDRATTR_TEXT_UPPERDIST
843 "/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObject"
844 "/DefaultProperties/SfxItemSet/SdrMetricItem/SfxInt32Item[@whichId='1073']",
846 // SDRATTR_TEXT_LOWERDIST
848 "/root/page/body/txt/anchored/SwAnchoredDrawObject/SdrObject"
849 "/DefaultProperties/SfxItemSet/SdrMetricItem/SfxInt32Item[@whichId='1074']",
852 // Check the textbox-shape import too
853 auto xShp
= getShape(1);
854 CPPUNIT_ASSERT(xShp
);
856 uno::Reference
<beans::XPropertySet
> xShapeProps(xShp
, uno::UNO_QUERY
);
858 SwFrameFormat
* pFrameFormat
= SwTextBoxHelper::getOtherTextBoxFormat(xShp
);
859 CPPUNIT_ASSERT(pFrameFormat
);
861 // The shape has these values to copy to the associated text frame after modification::
862 const tools::Long nLPaddng
863 = xShapeProps
->getPropertyValue("TextLeftDistance").get
<tools::Long
>();
864 const tools::Long nRPaddng
865 = xShapeProps
->getPropertyValue("TextRightDistance").get
<tools::Long
>();
866 const tools::Long nTPaddng
867 = xShapeProps
->getPropertyValue("TextUpperDistance").get
<tools::Long
>();
868 const tools::Long nBPaddng
869 = xShapeProps
->getPropertyValue("TextLowerDistance").get
<tools::Long
>();
871 CPPUNIT_ASSERT_EQUAL(tools::Long(1000), nLPaddng
);
872 CPPUNIT_ASSERT_EQUAL(tools::Long(2000), nRPaddng
);
873 CPPUNIT_ASSERT_EQUAL(tools::Long(3000), nTPaddng
);
874 CPPUNIT_ASSERT_EQUAL(tools::Long(4001), nBPaddng
);
876 // TODO: modify shape distance via UNO with text frame synchronization
877 // Check the textbox as well:
878 auto xTxFrm
= SwXTextFrame::CreateXTextFrame(*pFrameFormat
->GetDoc(), pFrameFormat
);
879 CPPUNIT_ASSERT(xTxFrm
);
880 uno::Reference
<beans::XPropertySet
> xFrameProps(xTxFrm
, uno::UNO_QUERY
);
882 const tools::Long nFrameLeftPaddng
883 = xFrameProps
->getPropertyValue("LeftBorderDistance").get
<tools::Long
>();
884 const tools::Long nFrameRightPaddng
885 = xFrameProps
->getPropertyValue("RightBorderDistance").get
<tools::Long
>();
886 const tools::Long nFrameTopPaddng
887 = xFrameProps
->getPropertyValue("TopBorderDistance").get
<tools::Long
>();
888 const tools::Long nFrameBottomPaddng
889 = xFrameProps
->getPropertyValue("BottomBorderDistance").get
<tools::Long
>();
891 // Check if the shape and frame have different setting
892 CPPUNIT_ASSERT_EQUAL(nLPaddng
, nFrameLeftPaddng
);
893 CPPUNIT_ASSERT_EQUAL(nRPaddng
, nFrameRightPaddng
);
894 CPPUNIT_ASSERT_EQUAL(nTPaddng
, nFrameTopPaddng
);
895 CPPUNIT_ASSERT_EQUAL(nBPaddng
, nFrameBottomPaddng
);
898 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testRedlineFlysInFootnote
)
900 loadURL("private:factory/swriter", nullptr);
901 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
902 CPPUNIT_ASSERT(pTextDoc
);
903 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
904 SwWrtShell
* pWrtShell
= pTextDoc
->GetDocShell()->GetWrtShell();
905 SwRootFrame
* pLayout(pWrtShell
->GetLayout());
906 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
907 pWrtShell
->InsertFootnote("");
908 CPPUNIT_ASSERT(pWrtShell
->IsCursorInFootnote());
910 SfxItemSet
flySet(pDoc
->GetAttrPool(),
911 svl::Items
<RES_FRM_SIZE
, RES_FRM_SIZE
, RES_ANCHOR
, RES_ANCHOR
>);
912 SwFormatFrameSize
size(SwFrameSize::Minimum
, 1000, 1000);
913 flySet
.Put(size
); // set a size, else we get 1 char per line...
914 SwFormatAnchor
anchor(RndStdIds::FLY_AT_CHAR
);
915 anchor
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
917 // first fly is in first footnote that will be deleted
918 /* SwFrameFormat const* pFly1 =*/pWrtShell
->NewFlyFrame(flySet
, /*bAnchValid=*/true);
919 pWrtShell
->Insert("quux");
921 pWrtShell
->SttEndDoc(false);
923 pWrtShell
->InsertFootnote("");
924 CPPUNIT_ASSERT(pWrtShell
->IsCursorInFootnote());
925 pWrtShell
->Insert("foo");
926 pWrtShell
->SplitNode(false);
927 pWrtShell
->Insert("bar");
928 pWrtShell
->SplitNode(false);
929 pWrtShell
->Insert("baz");
931 pWrtShell
->StartOfSection(false);
932 CPPUNIT_ASSERT(pWrtShell
->IsCursorInFootnote());
933 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 1, /*bBasicCall=*/false);
934 anchor
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
936 // second fly is in second footnote that is not deleted
937 SwFrameFormat
const* pFly
= pWrtShell
->NewFlyFrame(flySet
, /*bAnchValid=*/true);
938 CPPUNIT_ASSERT(pFly
!= nullptr);
940 pWrtShell
->GotoFly(pFly
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
941 pWrtShell
->Insert("abc");
942 pWrtShell
->SplitNode(false);
943 pWrtShell
->Insert("def");
944 pWrtShell
->SplitNode(false);
945 pWrtShell
->Insert("ghi");
947 dispatchCommand(mxComponent
, ".uno:TrackChanges", {});
948 // delete redline inside fly
949 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
950 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/true, 8, /*bBasicCall=*/false);
953 // pWrtShell->GotoFlyAnchor(); // sigh... why, now we're in the body...
954 pWrtShell
->SttEndDoc(false);
955 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/false, 1, /*bBasicCall=*/false);
956 pWrtShell
->GotoFootnoteText();
957 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
958 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/true, 7, /*bBasicCall=*/false);
960 pWrtShell
->EndSelect(); // ?
961 // delete first footnote
962 pWrtShell
->SttEndDoc(true);
963 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/true, 1, /*bBasicCall=*/false);
966 for (int i
= 0; i
< 2; ++i
)
968 if (i
== 1) // secondly, try with different anchor type
970 anchor
.SetType(RndStdIds::FLY_AT_PARA
);
971 SwPosition
pos(*anchor
.GetContentAnchor());
972 pos
.nContent
.Assign(nullptr, 0);
973 anchor
.SetAnchor(&pos
);
974 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
977 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
978 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
979 discardDumpedLayout();
980 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
981 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
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]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
987 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/merged",
988 "paraPropsNodeIndex", "17");
989 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
990 "nType", "PortionType::Para");
991 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
993 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
994 "PortionType::FootnoteNum");
995 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
997 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
998 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
999 discardDumpedLayout();
1000 pXmlDoc
= parseLayoutDump();
1002 { // show: nothing is merged
1003 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
1004 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
1005 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
1006 xmlXPathFreeObject(pXmlObj
);
1009 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1010 "PortionType::Footnote");
1011 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1012 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[2]", "nType",
1013 "PortionType::Footnote");
1014 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
1015 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1016 "nType", "PortionType::Para");
1017 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1019 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1020 "PortionType::FootnoteNum");
1021 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1022 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1023 "nType", "PortionType::Text");
1024 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1026 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
1027 "nType", "PortionType::Text");
1028 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[1]/Text[2]",
1030 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
1031 "nType", "PortionType::Para");
1032 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[2]/Text[1]",
1034 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
1035 "nType", "PortionType::Text");
1036 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[1]",
1038 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
1039 "nType", "PortionType::Text");
1040 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/anchored/fly[1]/txt[3]/Text[2]",
1042 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
1043 "PortionType::FootnoteNum");
1044 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
1045 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
1046 "PortionType::Text");
1047 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
1048 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType",
1049 "PortionType::Text");
1050 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
1051 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType",
1052 "PortionType::Para");
1053 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
1054 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType",
1055 "PortionType::Text");
1056 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
1057 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType",
1058 "PortionType::Text");
1059 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
1062 // anchor to 2nd (deleted) paragraph
1063 pWrtShell
->SttEndDoc(false);
1064 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1065 pWrtShell
->GotoFootnoteText();
1066 pWrtShell
->Down(false, 1);
1067 anchor
.SetType(RndStdIds::FLY_AT_CHAR
);
1068 anchor
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
1069 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
1071 for (int i
= 0; i
< 2; ++i
)
1073 if (i
== 1) // secondly, try with different anchor type
1075 anchor
.SetType(RndStdIds::FLY_AT_PARA
);
1076 SwPosition
pos(*anchor
.GetContentAnchor());
1077 pos
.nContent
.Assign(nullptr, 0);
1078 anchor
.SetAnchor(&pos
);
1079 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
1082 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
1083 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
1084 discardDumpedLayout();
1085 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
1087 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
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]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
1093 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1094 "PortionType::FootnoteNum");
1095 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1097 { // hide: no anchored object shown
1098 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//anchored");
1099 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
1100 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
1101 xmlXPathFreeObject(pXmlObj
);
1104 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
1105 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
1106 discardDumpedLayout();
1107 pXmlDoc
= parseLayoutDump();
1109 { // show: nothing is merged
1110 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
1111 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
1112 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
1113 xmlXPathFreeObject(pXmlObj
);
1116 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1117 "PortionType::Footnote");
1118 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1119 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[2]", "nType",
1120 "PortionType::Footnote");
1121 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
1122 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1123 "nType", "PortionType::Para");
1124 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1126 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1127 "PortionType::FootnoteNum");
1128 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1129 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
1130 "PortionType::FootnoteNum");
1131 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
1132 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
1133 "PortionType::Text");
1134 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
1135 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType",
1136 "PortionType::Text");
1137 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
1138 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
1139 "nType", "PortionType::Text");
1140 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[1]",
1142 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
1143 "nType", "PortionType::Text");
1144 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[1]/Text[2]",
1146 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
1147 "nType", "PortionType::Para");
1148 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[2]/Text[1]",
1150 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
1151 "nType", "PortionType::Text");
1152 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[1]",
1154 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
1155 "nType", "PortionType::Text");
1156 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/anchored/fly[1]/txt[3]/Text[2]",
1158 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType",
1159 "PortionType::Para");
1160 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
1161 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType",
1162 "PortionType::Text");
1163 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
1164 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType",
1165 "PortionType::Text");
1166 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
1169 // anchor to 3rd paragraph
1170 pWrtShell
->EndOfSection();
1171 pWrtShell
->SttEndDoc(false);
1172 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1173 pWrtShell
->GotoFootnoteText();
1174 pWrtShell
->EndOfSection();
1175 anchor
.SetType(RndStdIds::FLY_AT_CHAR
);
1176 anchor
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
1177 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
1179 for (int i
= 0; i
< 2; ++i
)
1181 if (i
== 1) // secondly, try with different anchor type
1183 anchor
.SetType(RndStdIds::FLY_AT_PARA
);
1184 SwPosition
pos(*anchor
.GetContentAnchor());
1185 pos
.nContent
.Assign(nullptr, 0);
1186 anchor
.SetAnchor(&pos
);
1187 pDoc
->SetAttr(anchor
, *const_cast<SwFrameFormat
*>(pFly
));
1190 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
1191 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
1192 discardDumpedLayout();
1193 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
1194 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "25");
1195 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1196 "PortionType::Footnote");
1197 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1198 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/merged", "paraPropsNodeIndex",
1200 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/merged",
1201 "paraPropsNodeIndex", "17");
1202 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1203 "nType", "PortionType::Para");
1204 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1206 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1207 "PortionType::FootnoteNum");
1208 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1210 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
1211 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
1212 discardDumpedLayout();
1213 pXmlDoc
= parseLayoutDump();
1215 { // show: nothing is merged
1216 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
1217 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
1218 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
1219 xmlXPathFreeObject(pXmlObj
);
1222 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "nType",
1223 "PortionType::Footnote");
1224 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[1]", "rText", "1");
1225 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[2]", "nType",
1226 "PortionType::Footnote");
1227 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Special[2]", "rText", "2");
1228 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1229 "nType", "PortionType::Para");
1230 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
1232 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "nType",
1233 "PortionType::FootnoteNum");
1234 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[1]/txt[1]/Special[1]", "rText", "1");
1235 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "nType",
1236 "PortionType::FootnoteNum");
1237 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Special[1]", "rText", "2");
1238 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "nType",
1239 "PortionType::Text");
1240 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[1]", "Portion", "fo");
1241 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "nType",
1242 "PortionType::Text");
1243 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[1]/Text[2]", "Portion", "o");
1244 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "nType",
1245 "PortionType::Para");
1246 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[2]/Text[1]", "Portion", "bar");
1247 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
1248 "nType", "PortionType::Text");
1249 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[1]",
1251 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
1252 "nType", "PortionType::Text");
1253 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[1]/Text[2]",
1255 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
1256 "nType", "PortionType::Para");
1257 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[2]/Text[1]",
1259 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
1260 "nType", "PortionType::Text");
1261 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[1]",
1263 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
1264 "nType", "PortionType::Text");
1265 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/anchored/fly[1]/txt[3]/Text[2]",
1267 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "nType",
1268 "PortionType::Text");
1269 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[1]", "Portion", "b");
1270 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "nType",
1271 "PortionType::Text");
1272 assertXPath(pXmlDoc
, "/root/page[1]/ftncont/ftn[2]/txt[3]/Text[2]", "Portion", "az");
1276 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf143239
)
1278 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf143239-1-min.odt");
1279 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
1281 // These are unstable on macOS and Win64 builds,
1282 // so only test that they restore original values for now
1283 OUString p2txt1Left
, p2txt2Left
, p3txt1Left
;
1286 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
1287 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly", 1);
1288 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top",
1291 = getXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "left");
1292 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[2]/anchored/fly", 1);
1293 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[2]/anchored/fly[1]/infos/bounds", "top",
1296 = getXPath(pXmlDoc
, "/root/page[2]/body/txt[2]/anchored/fly[1]/infos/bounds", "left");
1297 assertXPath(pXmlDoc
, "/root/page[3]/body/txt[1]/anchored/fly", 1);
1298 assertXPath(pXmlDoc
, "/root/page[3]/body/txt[1]/anchored/fly[1]/infos/bounds", "top",
1301 = getXPath(pXmlDoc
, "/root/page[3]/body/txt[1]/anchored/fly[1]/infos/bounds", "left");
1302 assertXPath(pXmlDoc
, "/root/page", 3);
1303 discardDumpedLayout();
1306 pWrtShell
->SelAll();
1307 pWrtShell
->Delete();
1309 Scheduler::ProcessEventsToIdle();
1312 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
1313 // now the 1st fly was on page 1, and the fly on page 2 was the 2nd one
1314 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly", 1);
1315 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top",
1317 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "left",
1319 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[2]/anchored/fly", 1);
1320 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[2]/anchored/fly[1]/infos/bounds", "top",
1322 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[2]/anchored/fly[1]/infos/bounds", "left",
1324 assertXPath(pXmlDoc
, "/root/page[3]/body/txt[1]/anchored/fly", 1);
1325 assertXPath(pXmlDoc
, "/root/page[3]/body/txt[1]/anchored/fly[1]/infos/bounds", "top",
1327 assertXPath(pXmlDoc
, "/root/page[3]/body/txt[1]/anchored/fly[1]/infos/bounds", "left",
1329 assertXPath(pXmlDoc
, "/root/page", 3);
1330 discardDumpedLayout();
1334 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTableOverlapFooterFly
)
1336 // Load a document that has a fly anchored in the footer.
1337 // It also has a table which initially overlaps with the fly, but then moves to the next page.
1338 load(DATA_DIRECTORY
, "footer-fly-table.fodt");
1339 xmlDocUniquePtr pLayout
= parseLayoutDump();
1340 // no fly portions, was: 8
1343 "/root/page[2]/body/tab[1]/row[5]/cell[5]/txt[1]/Special[@nType='PortionType::Fly']", 0);
1344 // one line break, was: 5
1345 assertXPath(pLayout
, "/root/page[2]/body/tab[1]/row[5]/cell[5]/txt[1]/LineBreak", 1);
1346 // one text portion, was: 1
1347 assertXPath(pLayout
, "/root/page[2]/body/tab[1]/row[5]/cell[5]/txt[1]/Text", 1);
1348 assertXPath(pLayout
, "/root/page[2]/body/tab[1]/row[5]/cell[5]/txt[1]/Text", "Portion",
1349 "Abc def ghi jkl mno pqr stu vwx yz.");
1351 // tdf#134782 height was: 379
1352 assertXPath(pLayout
, "/root/page[2]/body/tab[1]/row[5]/cell[5]/txt[1]/infos/bounds", "height",
1356 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, TestTdf134277
)
1358 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf134277.docx");
1359 CPPUNIT_ASSERT(pDoc
);
1360 SwDocShell
* pShell
= pDoc
->GetDocShell();
1362 std::shared_ptr
<GDIMetaFile
> xMetaFile
= pShell
->GetPreviewMetaFile();
1363 MetafileXmlDump dumper
;
1365 xmlDocUniquePtr pXmlDoc
= dumpAndParse(dumper
, *xMetaFile
);
1366 CPPUNIT_ASSERT(pXmlDoc
);
1368 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "/metafile/push/push/push/layoutmode[2]");
1369 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
1370 CPPUNIT_ASSERT_EQUAL_MESSAGE("Bad position of shape in page break!", 0,
1371 xmlXPathNodeSetGetLength(pXmlNodes
));
1374 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf116486
)
1376 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf116486.docx");
1377 CPPUNIT_ASSERT(pDoc
);
1378 OUString aTop
= parseDump("/root/page/body/txt/Special[1]", "nHeight");
1379 CPPUNIT_ASSERT_EQUAL(OUString("4006"), aTop
);
1382 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, TestTdf142080
)
1384 // this caused an infinite loop
1385 load(DATA_DIRECTORY
, "fdo43573-2-min.docx");
1387 xmlDocUniquePtr pLayout
= parseLayoutDump();
1388 // check the first paragraph on page 9 with its fly; the column was empty too
1389 assertXPath(pLayout
, "/root/page[9]/body/section[1]/column[1]/body/txt[1]/Text[1]", "Portion",
1390 "De kleur u (rood) in het rechtervlak (R), de kleur r (wit) beneden (D),");
1391 SwTwips nPage9Top
= getXPath(pLayout
, "/root/page[9]/infos/bounds", "top").toInt32();
1394 "/root/page[9]/body/section[1]/column[1]/body/txt[1]/anchored/fly[1]/notxt/infos/bounds",
1395 "top", OUString::number(nPage9Top
+ 1460));
1398 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf128198
)
1400 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf128198-1.docx");
1401 CPPUNIT_ASSERT(pDoc
);
1402 xmlDocUniquePtr pLayout
= parseLayoutDump();
1403 // the problem was that line 5 was truncated at "this "
1404 // due to the fly anchored in previous paragraph
1405 assertXPath(pLayout
, "/root/page/body/txt[2]/LineBreak[5]", "Line",
1406 "to access any service, any time, anywhere. From this perspective, satellite "
1408 assertXPath(pLayout
, "/root/page/body/txt[2]/LineBreak[6]", "Line", "significant advantages. ");
1411 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testNoLineBreakAtSlash
)
1413 load(DATA_DIRECTORY
, "no-line-break-at-slash.fodt");
1414 xmlDocUniquePtr pLayout
= parseLayoutDump();
1416 // the line break was between "Foostrasse 13/c/" and "2"
1417 xmlXPathObjectPtr pXmlObj
= getXPathNode(pLayout
, "/root/page[1]/body/txt[1]/child::*[2]");
1418 CPPUNIT_ASSERT_EQUAL(std::string("Text"), std::string(reinterpret_cast<char const*>(
1419 pXmlObj
->nodesetval
->nodeTab
[0]->name
)));
1420 xmlXPathFreeObject(pXmlObj
);
1421 pXmlObj
= getXPathNode(pLayout
, "/root/page[1]/body/txt[1]/child::*[3]");
1422 CPPUNIT_ASSERT_EQUAL(std::string("LineBreak"), std::string(reinterpret_cast<char const*>(
1423 pXmlObj
->nodesetval
->nodeTab
[0]->name
)));
1424 xmlXPathFreeObject(pXmlObj
);
1425 pXmlObj
= getXPathNode(pLayout
, "/root/page[1]/body/txt[1]/child::*[4]");
1426 CPPUNIT_ASSERT_EQUAL(std::string("Text"), std::string(reinterpret_cast<char const*>(
1427 pXmlObj
->nodesetval
->nodeTab
[0]->name
)));
1428 xmlXPathFreeObject(pXmlObj
);
1429 pXmlObj
= getXPathNode(pLayout
, "/root/page[1]/body/txt[1]/child::*[5]");
1430 CPPUNIT_ASSERT_EQUAL(std::string("Special"), std::string(reinterpret_cast<char const*>(
1431 pXmlObj
->nodesetval
->nodeTab
[0]->name
)));
1432 xmlXPathFreeObject(pXmlObj
);
1433 pXmlObj
= getXPathNode(pLayout
, "/root/page[1]/body/txt[1]/child::*[6]");
1434 CPPUNIT_ASSERT_EQUAL(std::string("Text"), std::string(reinterpret_cast<char const*>(
1435 pXmlObj
->nodesetval
->nodeTab
[0]->name
)));
1436 xmlXPathFreeObject(pXmlObj
);
1437 pXmlObj
= getXPathNode(pLayout
, "/root/page[1]/body/txt[1]/child::*[7]");
1438 CPPUNIT_ASSERT_EQUAL(std::string("LineBreak"), std::string(reinterpret_cast<char const*>(
1439 pXmlObj
->nodesetval
->nodeTab
[0]->name
)));
1440 xmlXPathFreeObject(pXmlObj
);
1441 pXmlObj
= getXPathNode(pLayout
, "/root/page[1]/body/txt[1]/child::*[8]");
1442 CPPUNIT_ASSERT_EQUAL(std::string("Finish"), std::string(reinterpret_cast<char const*>(
1443 pXmlObj
->nodesetval
->nodeTab
[0]->name
)));
1444 xmlXPathFreeObject(pXmlObj
);
1446 assertXPath(pLayout
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "Blah blah bla bla bla ");
1447 assertXPath(pLayout
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "Foostrasse");
1448 assertXPath(pLayout
, "/root/page[1]/body/txt[1]/Text[3]", "Portion", "13/c/2, etc.");
1451 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf106153
)
1453 load(DATA_DIRECTORY
, "tdf106153.docx");
1454 xmlDocUniquePtr pDump
= parseLayoutDump();
1456 const sal_Int64 nPageValLeft
= getXPath(pDump
, "/root/page/infos/bounds", "left").toInt64();
1457 const sal_Int64 nPageValTop
= getXPath(pDump
, "/root/page/infos/bounds", "top").toInt64();
1458 const sal_Int64 nPageValRight
= getXPath(pDump
, "/root/page/infos/bounds", "right").toInt64();
1459 const sal_Int64 nPageValBottom
= getXPath(pDump
, "/root/page/infos/bounds", "bottom").toInt64();
1461 const sal_Int64 nShape1ValTop
1462 = getXPath(pDump
, "/root/page/body/txt/anchored/fly[1]/infos/bounds", "top").toInt64();
1463 const sal_Int64 nShape2ValLeft
1464 = getXPath(pDump
, "/root/page/body/txt/anchored/fly[2]/infos/bounds", "left").toInt64();
1465 const sal_Int64 nShape3ValRight
1466 = getXPath(pDump
, "/root/page/body/txt/anchored/fly[3]/infos/bounds", "right").toInt64();
1467 const sal_Int64 nShape4ValBottom
1468 = getXPath(pDump
, "/root/page/body/txt/anchored/fly[4]/infos/bounds", "bottom").toInt64();
1470 CPPUNIT_ASSERT_MESSAGE("The whole top textbox is inside the page!",
1471 nPageValTop
> nShape1ValTop
);
1472 CPPUNIT_ASSERT_MESSAGE("The whole left textbox is inside the page!",
1473 nPageValLeft
> nShape2ValLeft
);
1474 CPPUNIT_ASSERT_MESSAGE("The whole right textbox is inside the page!",
1475 nPageValRight
< nShape3ValRight
);
1476 CPPUNIT_ASSERT_MESSAGE("The whole bottom textbox is inside the page!",
1477 nPageValBottom
< nShape4ValBottom
);
1480 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testRedlineFlysInFlys
)
1482 loadURL("private:factory/swriter", nullptr);
1483 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
1484 CPPUNIT_ASSERT(pTextDoc
);
1485 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
1486 SwWrtShell
* pWrtShell
= pTextDoc
->GetDocShell()->GetWrtShell();
1487 SwRootFrame
* pLayout(pWrtShell
->GetLayout());
1488 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
1489 pWrtShell
->Insert("foo");
1490 pWrtShell
->SplitNode(false);
1491 pWrtShell
->Insert("bar");
1492 pWrtShell
->SplitNode(false);
1493 pWrtShell
->Insert("baz");
1494 SfxItemSet
flySet(pDoc
->GetAttrPool(),
1495 svl::Items
<RES_FRM_SIZE
, RES_FRM_SIZE
, RES_ANCHOR
, RES_ANCHOR
>);
1496 SwFormatFrameSize
size(SwFrameSize::Minimum
, 1000, 1000);
1497 flySet
.Put(size
); // set a size, else we get 1 char per line...
1498 pWrtShell
->StartOfSection(false);
1499 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1500 SwFormatAnchor
anchor1(RndStdIds::FLY_AT_CHAR
);
1501 anchor1
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
1502 flySet
.Put(anchor1
);
1503 SwFrameFormat
const* pFly1
= pWrtShell
->NewFlyFrame(flySet
, /*bAnchValid=*/true);
1504 CPPUNIT_ASSERT(pFly1
!= nullptr);
1506 pWrtShell
->GotoFly(pFly1
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
1507 pWrtShell
->Insert("abc");
1508 pWrtShell
->SplitNode(false);
1509 pWrtShell
->Insert("def");
1510 pWrtShell
->SplitNode(false);
1511 pWrtShell
->Insert("ghi");
1513 SwFormatAnchor
anchor2(RndStdIds::FLY_AT_CHAR
);
1514 pWrtShell
->StartOfSection(false); // start of fly...
1515 anchor2
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
1516 flySet
.Put(anchor2
);
1517 SwFrameFormat
const* pFly2
= pWrtShell
->NewFlyFrame(flySet
, /*bAnchValid=*/true);
1518 CPPUNIT_ASSERT(pFly2
!= nullptr);
1520 pWrtShell
->GotoFly(pFly2
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
1521 pWrtShell
->Insert("jkl");
1522 pWrtShell
->SplitNode(false);
1523 pWrtShell
->Insert("mno");
1524 pWrtShell
->SplitNode(false);
1525 pWrtShell
->Insert("pqr");
1527 dispatchCommand(mxComponent
, ".uno:TrackChanges", {});
1528 // delete redline inside fly2
1529 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1530 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/true, 8, /*bBasicCall=*/false);
1531 pWrtShell
->Delete();
1533 // delete redline inside fly1
1534 pWrtShell
->GotoFly(pFly1
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
1535 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1536 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/true, 7, /*bBasicCall=*/false);
1537 pWrtShell
->Delete();
1539 pWrtShell
->ClearMark(); // otherwise it refuses to leave the fly...
1540 pWrtShell
->SttEndDoc(true); // note: SttDoc actually moves to start of fly?
1541 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1542 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/true, 7, /*bBasicCall=*/false);
1543 pWrtShell
->Delete();
1545 for (int i
= 0; i
< 2; ++i
)
1547 if (i
== 1) // secondly, try with different anchor type
1549 anchor1
.SetType(RndStdIds::FLY_AT_PARA
);
1550 SwPosition
pos(*anchor1
.GetContentAnchor());
1551 pos
.nContent
.Assign(nullptr, 0);
1552 anchor1
.SetAnchor(&pos
);
1553 pDoc
->SetAttr(anchor1
, *const_cast<SwFrameFormat
*>(pFly1
));
1554 anchor2
.SetType(RndStdIds::FLY_AT_PARA
);
1555 pos
.nNode
= anchor2
.GetContentAnchor()->nNode
;
1556 anchor2
.SetAnchor(&pos
);
1557 pDoc
->SetAttr(anchor2
, *const_cast<SwFrameFormat
*>(pFly2
));
1560 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
1561 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
1562 discardDumpedLayout();
1563 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
1564 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1565 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
1566 "paraPropsNodeIndex", "6");
1569 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/merged",
1570 "paraPropsNodeIndex", "11");
1573 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1574 "nType", "PortionType::Para");
1577 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1579 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1580 "PortionType::Fly"); // remove???
1581 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1582 "PortionType::Lay");
1583 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1585 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1586 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1588 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
1589 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
1590 discardDumpedLayout();
1591 pXmlDoc
= parseLayoutDump();
1593 { // show: nothing is merged
1594 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
1595 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
1596 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
1597 xmlXPathFreeObject(pXmlObj
);
1602 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1603 "nType", "PortionType::Text");
1606 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1610 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
1611 "nType", "PortionType::Text");
1614 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
1618 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
1619 "nType", "PortionType::Para");
1622 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
1626 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
1627 "nType", "PortionType::Text");
1630 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
1634 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
1635 "nType", "PortionType::Text");
1638 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
1640 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1641 "PortionType::Fly"); // remove???
1642 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1643 "PortionType::Text");
1644 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1646 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1647 "PortionType::Text");
1648 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1650 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1651 "PortionType::Para");
1652 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1654 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1655 "PortionType::Text");
1656 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1658 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1659 "PortionType::Text");
1660 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1662 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1663 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1664 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1665 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1666 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1667 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1668 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1669 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1670 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1671 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1674 // anchor to 2nd (deleted) paragraph
1675 // also, switch the in-fly anchoring to the other fly, for additional fun!
1676 pWrtShell
->StartOfSection();
1677 pWrtShell
->Down(false, 1);
1678 anchor2
.SetType(RndStdIds::FLY_AT_CHAR
);
1679 anchor2
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
1680 pDoc
->SetAttr(anchor2
, *const_cast<SwFrameFormat
*>(pFly2
));
1681 pWrtShell
->GotoFly(pFly2
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
1682 pWrtShell
->Down(false, 1);
1683 anchor1
.SetType(RndStdIds::FLY_AT_CHAR
);
1684 anchor1
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
1685 pDoc
->SetAttr(anchor1
, *const_cast<SwFrameFormat
*>(pFly1
));
1687 for (int i
= 0; i
< 2; ++i
)
1689 if (i
== 1) // secondly, try with different anchor type
1691 anchor1
.SetType(RndStdIds::FLY_AT_PARA
);
1692 SwPosition
pos(*anchor1
.GetContentAnchor());
1693 pos
.nContent
.Assign(nullptr, 0);
1694 anchor1
.SetAnchor(&pos
);
1695 pDoc
->SetAttr(anchor1
, *const_cast<SwFrameFormat
*>(pFly1
));
1696 anchor2
.SetType(RndStdIds::FLY_AT_PARA
);
1697 pos
.nNode
= anchor2
.GetContentAnchor()->nNode
;
1698 anchor2
.SetAnchor(&pos
);
1699 pDoc
->SetAttr(anchor2
, *const_cast<SwFrameFormat
*>(pFly2
));
1702 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
1703 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
1704 discardDumpedLayout();
1705 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
1706 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1707 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1708 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1710 { // hide: no anchored object shown
1711 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//anchored");
1712 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
1713 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
1714 xmlXPathFreeObject(pXmlObj
);
1717 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
1718 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
1719 discardDumpedLayout();
1720 pXmlDoc
= parseLayoutDump();
1722 { // show: nothing is merged
1723 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
1724 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
1725 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
1726 xmlXPathFreeObject(pXmlObj
);
1729 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1730 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1731 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1732 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1733 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1734 "PortionType::Text");
1735 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1737 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1738 "PortionType::Text");
1739 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1743 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[1]",
1744 "nType", "PortionType::Text");
1747 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[1]",
1751 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[2]",
1752 "nType", "PortionType::Text");
1755 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[1]/Text[2]",
1759 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[2]/Text[1]",
1760 "nType", "PortionType::Para");
1763 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[2]/Text[1]",
1767 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[1]",
1768 "nType", "PortionType::Text");
1771 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[1]",
1775 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[2]",
1776 "nType", "PortionType::Text");
1779 "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/anchored[1]/fly[1]/txt[3]/Text[2]",
1781 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Special[1]", "nType",
1782 "PortionType::Fly"); // remove???
1783 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1784 "PortionType::Lay");
1785 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1787 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1788 "PortionType::Text");
1789 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1791 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1792 "PortionType::Text");
1793 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1795 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1796 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1797 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1798 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1799 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1800 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1803 // anchor to 3rd paragraph
1804 pWrtShell
->SttEndDoc(false);
1805 anchor1
.SetType(RndStdIds::FLY_AT_CHAR
);
1806 anchor1
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
1807 pDoc
->SetAttr(anchor1
, *const_cast<SwFrameFormat
*>(pFly1
));
1808 pWrtShell
->GotoFly(pFly1
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
1809 pWrtShell
->EndOfSection();
1810 anchor2
.SetType(RndStdIds::FLY_AT_CHAR
);
1811 anchor2
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
1812 pDoc
->SetAttr(anchor2
, *const_cast<SwFrameFormat
*>(pFly2
));
1814 for (int i
= 0; i
< 2; ++i
)
1816 if (i
== 1) // secondly, try with different anchor type
1818 anchor1
.SetType(RndStdIds::FLY_AT_PARA
);
1819 SwPosition
pos(*anchor1
.GetContentAnchor());
1820 pos
.nContent
.Assign(nullptr, 0);
1821 anchor1
.SetAnchor(&pos
);
1822 pDoc
->SetAttr(anchor1
, *const_cast<SwFrameFormat
*>(pFly1
));
1823 anchor2
.SetType(RndStdIds::FLY_AT_PARA
);
1824 pos
.nNode
= anchor2
.GetContentAnchor()->nNode
;
1825 anchor2
.SetAnchor(&pos
);
1826 pDoc
->SetAttr(anchor2
, *const_cast<SwFrameFormat
*>(pFly2
));
1829 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
1830 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
1831 discardDumpedLayout();
1832 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
1833 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
1834 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
1835 "paraPropsNodeIndex", "6");
1838 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/merged",
1839 "paraPropsNodeIndex", "11");
1842 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1843 "nType", "PortionType::Para");
1846 "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
1848 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
1849 "PortionType::Fly"); // remove???
1850 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1851 "PortionType::Lay");
1852 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1854 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
1855 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
1857 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
1858 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
1859 discardDumpedLayout();
1860 pXmlDoc
= parseLayoutDump();
1862 { // show: nothing is merged
1863 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
1864 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
1865 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
1866 xmlXPathFreeObject(pXmlObj
);
1869 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
1870 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
1871 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
1872 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
1873 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
1874 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
1875 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "nType",
1876 "PortionType::Text");
1877 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
1879 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "nType",
1880 "PortionType::Text");
1881 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
1883 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "nType",
1884 "PortionType::Para");
1885 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
1889 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[1]",
1890 "nType", "PortionType::Text");
1893 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[1]",
1897 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[2]",
1898 "nType", "PortionType::Text");
1901 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[1]/Text[2]",
1905 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[2]/Text[1]",
1906 "nType", "PortionType::Para");
1909 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[2]/Text[1]",
1913 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[1]",
1914 "nType", "PortionType::Text");
1917 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[1]",
1921 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[2]",
1922 "nType", "PortionType::Text");
1925 "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/anchored[1]/fly[1]/txt[3]/Text[2]",
1927 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "nType",
1928 "PortionType::Text");
1929 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Special[1]", "nType",
1930 "PortionType::Fly"); // remove???
1931 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
1933 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "nType",
1934 "PortionType::Text");
1935 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
1937 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
1938 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
1939 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
1940 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
1944 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testRedlineFlysAtFlys
)
1946 loadURL("private:factory/swriter", nullptr);
1947 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
1948 CPPUNIT_ASSERT(pTextDoc
);
1949 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
1950 SwWrtShell
* pWrtShell
= pTextDoc
->GetDocShell()->GetWrtShell();
1951 SwRootFrame
* pLayout(pWrtShell
->GetLayout());
1952 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
1953 pWrtShell
->Insert("foo");
1954 pWrtShell
->SplitNode(false);
1955 pWrtShell
->Insert("bar");
1956 pWrtShell
->SplitNode(false);
1957 pWrtShell
->Insert("baz");
1958 SfxItemSet
flySet(pDoc
->GetAttrPool(),
1959 svl::Items
<RES_FRM_SIZE
, RES_FRM_SIZE
, RES_ANCHOR
, RES_ANCHOR
>);
1960 SwFormatFrameSize
size(SwFrameSize::Minimum
, 1000, 1000);
1961 flySet
.Put(size
); // set a size, else we get 1 char per line...
1962 pWrtShell
->StartOfSection(false);
1963 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1964 SwFormatAnchor
anchor1(RndStdIds::FLY_AT_CHAR
);
1965 anchor1
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
1966 flySet
.Put(anchor1
);
1967 SwFrameFormat
const* pFly1
= pWrtShell
->NewFlyFrame(flySet
, /*bAnchValid=*/true);
1968 CPPUNIT_ASSERT(pFly1
!= nullptr);
1970 pWrtShell
->GotoFly(pFly1
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
1971 pWrtShell
->Insert("abc");
1972 pWrtShell
->SplitNode(false);
1973 pWrtShell
->Insert("def");
1974 pWrtShell
->SplitNode(false);
1975 pWrtShell
->Insert("ghi");
1977 SwFormatAnchor
anchor2(RndStdIds::FLY_AT_FLY
);
1978 SwPosition
pos(*pFly1
->GetContent().GetContentIdx());
1979 anchor2
.SetAnchor(&pos
);
1980 flySet
.Put(anchor2
);
1981 SwFrameFormat
const* pFly2
= pWrtShell
->NewFlyFrame(flySet
, /*bAnchValid=*/true);
1982 CPPUNIT_ASSERT(pFly2
!= nullptr);
1984 pWrtShell
->GotoFly(pFly2
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
1985 pWrtShell
->Insert("jkl");
1986 pWrtShell
->SplitNode(false);
1987 pWrtShell
->Insert("mno");
1988 pWrtShell
->SplitNode(false);
1989 pWrtShell
->Insert("pqr");
1991 dispatchCommand(mxComponent
, ".uno:TrackChanges", {});
1992 // delete redline inside fly2
1993 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
1994 pWrtShell
->Left(CRSR_SKIP_CHARS
, /*bSelect=*/true, 8, /*bBasicCall=*/false);
1995 pWrtShell
->Delete();
1997 // delete redline inside fly1
1998 pWrtShell
->GotoFly(pFly1
->GetName(), FLYCNTTYPE_FRM
, /*bSelFrame=*/false);
1999 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
2000 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/true, 7, /*bBasicCall=*/false);
2001 pWrtShell
->Delete();
2003 pWrtShell
->ClearMark(); // otherwise it refuses to leave the fly...
2004 pWrtShell
->SttEndDoc(true); // note: SttDoc actually moves to start of fly?
2005 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/false, 2, /*bBasicCall=*/false);
2006 pWrtShell
->Right(CRSR_SKIP_CHARS
, /*bSelect=*/true, 7, /*bBasicCall=*/false);
2007 pWrtShell
->Delete();
2009 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
2010 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
2011 discardDumpedLayout();
2012 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2013 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
2014 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/merged",
2015 "paraPropsNodeIndex", "6");
2016 assertXPath(pXmlDoc
,
2017 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/merged",
2018 "paraPropsNodeIndex", "11");
2019 assertXPath(pXmlDoc
,
2020 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2021 "nType", "PortionType::Para");
2022 assertXPath(pXmlDoc
,
2023 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2025 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
2026 "PortionType::Fly"); // remove???
2027 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
2028 "PortionType::Lay");
2029 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
2031 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2032 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
2034 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
2035 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
2036 discardDumpedLayout();
2037 pXmlDoc
= parseLayoutDump();
2039 { // show: nothing is merged
2040 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
2041 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
2042 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
2043 xmlXPathFreeObject(pXmlObj
);
2046 assertXPath(pXmlDoc
,
2047 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2048 "nType", "PortionType::Text");
2049 assertXPath(pXmlDoc
,
2050 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2052 assertXPath(pXmlDoc
,
2053 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
2054 "nType", "PortionType::Text");
2055 assertXPath(pXmlDoc
,
2056 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
2058 assertXPath(pXmlDoc
,
2059 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
2060 "nType", "PortionType::Para");
2061 assertXPath(pXmlDoc
,
2062 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
2064 assertXPath(pXmlDoc
,
2065 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
2066 "nType", "PortionType::Text");
2067 assertXPath(pXmlDoc
,
2068 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
2070 assertXPath(pXmlDoc
,
2071 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
2072 "nType", "PortionType::Text");
2073 assertXPath(pXmlDoc
,
2074 "/root/page[1]/body/txt[1]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
2076 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Special[1]", "nType",
2077 "PortionType::Fly"); // remove???
2078 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "nType",
2079 "PortionType::Text");
2080 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
2082 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "nType",
2083 "PortionType::Text");
2084 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
2086 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "nType",
2087 "PortionType::Para");
2088 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
2090 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "nType",
2091 "PortionType::Text");
2092 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
2094 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "nType",
2095 "PortionType::Text");
2096 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
2098 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
2099 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
2100 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
2101 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
2102 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
2103 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
2104 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
2105 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
2106 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
2107 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
2109 // anchor to 2nd (deleted) paragraph
2110 pWrtShell
->StartOfSection();
2111 pWrtShell
->Down(false, 1);
2112 anchor1
.SetType(RndStdIds::FLY_AT_CHAR
);
2113 anchor1
.SetAnchor(pWrtShell
->GetCursor()->GetPoint());
2114 pDoc
->SetAttr(anchor1
, *const_cast<SwFrameFormat
*>(pFly1
));
2116 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
2117 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
2118 discardDumpedLayout();
2119 pXmlDoc
= parseLayoutDump();
2120 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "19");
2121 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2122 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foaz");
2124 { // hide: no anchored object shown
2125 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//anchored");
2126 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
2127 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
2128 xmlXPathFreeObject(pXmlObj
);
2131 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
2132 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
2133 discardDumpedLayout();
2134 pXmlDoc
= parseLayoutDump();
2136 { // show: nothing is merged
2137 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
2138 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
2139 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
2140 xmlXPathFreeObject(pXmlObj
);
2143 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
2144 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
2145 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
2146 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
2147 assertXPath(pXmlDoc
,
2148 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2149 "nType", "PortionType::Text");
2150 assertXPath(pXmlDoc
,
2151 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[1]",
2153 assertXPath(pXmlDoc
,
2154 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
2155 "nType", "PortionType::Text");
2156 assertXPath(pXmlDoc
,
2157 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[1]/Text[2]",
2159 assertXPath(pXmlDoc
,
2160 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
2161 "nType", "PortionType::Para");
2162 assertXPath(pXmlDoc
,
2163 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[2]/Text[1]",
2165 assertXPath(pXmlDoc
,
2166 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
2167 "nType", "PortionType::Text");
2168 assertXPath(pXmlDoc
,
2169 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[1]",
2171 assertXPath(pXmlDoc
,
2172 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
2173 "nType", "PortionType::Text");
2174 assertXPath(pXmlDoc
,
2175 "/root/page[1]/body/txt[2]/anchored/fly[1]/anchored[1]/fly[1]/txt[3]/Text[2]",
2177 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "nType",
2178 "PortionType::Text");
2179 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Special[1]", "nType",
2180 "PortionType::Fly"); // remove???
2181 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[1]", "Portion",
2183 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "nType",
2184 "PortionType::Text");
2185 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[1]/Text[2]", "Portion",
2187 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "nType",
2188 "PortionType::Para");
2189 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[2]/Text[1]", "Portion",
2191 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "nType",
2192 "PortionType::Text");
2193 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[1]", "Portion",
2195 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "nType",
2196 "PortionType::Text");
2197 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly[1]/txt[3]/Text[2]", "Portion",
2199 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Para");
2200 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "bar");
2201 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "nType", "PortionType::Text");
2202 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[1]", "Portion", "b");
2203 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "nType", "PortionType::Text");
2204 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/Text[2]", "Portion", "az");
2207 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testRedlineSections
)
2209 createSwDoc(DATA_DIRECTORY
, "redline_sections.fodt");
2210 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
2211 CPPUNIT_ASSERT(pTextDoc
);
2212 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
2213 SwRootFrame
* pLayout(pDoc
->getIDocumentLayoutAccess().GetCurrentLayout());
2214 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
2216 // verify after load
2217 CheckRedlineSectionsHidden();
2219 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
2220 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
2221 // why is this needed explicitly?
2222 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2223 discardDumpedLayout();
2224 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2226 // show: nothing is merged
2227 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
2228 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
2229 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
2230 xmlXPathFreeObject(pXmlObj
);
2231 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
2232 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
2233 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
2234 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
2236 assertXPath(pXmlDoc
, "/root/page[1]/body/section[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
2237 "nType", "PortionType::Para");
2238 assertXPath(pXmlDoc
, "/root/page[1]/body/section[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
2239 "Portion", "FRAME");
2240 assertXPath(pXmlDoc
, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "nType",
2241 "PortionType::Para");
2242 assertXPath(pXmlDoc
, "/root/page[1]/body/section[1]/txt[1]/Text[1]", "Portion", "bar");
2243 assertXPath(pXmlDoc
, "/root/page[1]/body/section[1]/txt[2]/Text[1]", "nType",
2244 "PortionType::Para");
2245 assertXPath(pXmlDoc
, "/root/page[1]/body/section[1]/txt[2]/Text[1]", "Portion", "baz");
2246 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Text");
2247 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "b");
2248 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[2]", "nType", "PortionType::Text");
2249 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[2]", "Portion", "lah");
2250 assertXPath(pXmlDoc
, "/root/page[1]/body/section[2]/txt[1]/Text[1]", "nType",
2251 "PortionType::Text");
2252 assertXPath(pXmlDoc
, "/root/page[1]/body/section[2]/txt[1]/Text[1]", "Portion", "fo");
2253 assertXPath(pXmlDoc
, "/root/page[1]/body/section[2]/txt[1]/Text[2]", "nType",
2254 "PortionType::Text");
2255 assertXPath(pXmlDoc
, "/root/page[1]/body/section[2]/txt[1]/Text[2]", "Portion", "o");
2256 assertXPath(pXmlDoc
, "/root/page[1]/body/section[2]/txt[2]/Text[1]", "nType",
2257 "PortionType::Para");
2258 assertXPath(pXmlDoc
, "/root/page[1]/body/section[2]/txt[2]/Text[1]", "Portion", "bar");
2259 assertXPath(pXmlDoc
, "/root/page[1]/body/section[2]/txt[3]/Text[1]", "nType",
2260 "PortionType::Text");
2261 assertXPath(pXmlDoc
, "/root/page[1]/body/section[2]/txt[3]/Text[1]", "Portion", "b");
2262 assertXPath(pXmlDoc
, "/root/page[1]/body/section[2]/txt[3]/Text[2]", "nType",
2263 "PortionType::Text");
2264 assertXPath(pXmlDoc
, "/root/page[1]/body/section[2]/txt[3]/Text[2]", "Portion", "lah");
2266 // verify after hide
2267 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
2268 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
2269 // why is this needed explicitly?
2270 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2271 discardDumpedLayout();
2272 CheckRedlineSectionsHidden();
2275 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, TDF69647_images
)
2277 createSwDoc(DATA_DIRECTORY
, "tdf69647_images.odt");
2278 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
2279 CPPUNIT_ASSERT(pTextDoc
);
2280 CPPUNIT_ASSERT_EQUAL_MESSAGE("Number of pages does not match!", 2, getPages());
2283 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, TDF69647_text
)
2285 createSwDoc(DATA_DIRECTORY
, "tdf69647_text.docx");
2286 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
2287 CPPUNIT_ASSERT(pTextDoc
);
2288 CPPUNIT_ASSERT_EQUAL_MESSAGE("Number of pages does not match!", 2, getPages());
2291 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testRedlineTables
)
2293 createSwDoc(DATA_DIRECTORY
, "redline_table.fodt");
2294 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
2295 CPPUNIT_ASSERT(pTextDoc
);
2296 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
2297 SwRootFrame
* pLayout(pDoc
->getIDocumentLayoutAccess().GetCurrentLayout());
2298 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
2300 // verify after load
2301 discardDumpedLayout();
2302 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2303 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "12");
2304 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2305 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foar");
2307 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
2308 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
2309 // why is this needed explicitly?
2310 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2311 discardDumpedLayout();
2312 pXmlDoc
= parseLayoutDump();
2314 // show: nothing is merged
2315 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "//merged");
2316 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
2317 CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlNodes
));
2318 xmlXPathFreeObject(pXmlObj
);
2319 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Text");
2320 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "fo");
2321 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "nType", "PortionType::Text");
2322 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[2]", "Portion", "o");
2324 assertXPath(pXmlDoc
,
2325 "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
2326 "nType", "PortionType::Para");
2327 assertXPath(pXmlDoc
,
2328 "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/anchored/fly[1]/txt[1]/Text[1]",
2329 "Portion", "FRAME");
2330 assertXPath(pXmlDoc
, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/Text[1]", "nType",
2331 "PortionType::Para");
2332 assertXPath(pXmlDoc
, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/Text[1]", "Portion",
2334 assertXPath(pXmlDoc
, "/root/page[1]/body/tab[1]/row[2]/cell[2]/txt[1]/Text[1]", "nType",
2335 "PortionType::Para");
2336 assertXPath(pXmlDoc
, "/root/page[1]/body/tab[1]/row[2]/cell[2]/txt[1]/Text[1]", "Portion",
2338 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "nType", "PortionType::Text");
2339 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[1]", "Portion", "b");
2340 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[2]", "nType", "PortionType::Text");
2341 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/Text[2]", "Portion", "ar");
2343 // verify after hide
2344 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
2345 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
2346 // why is this needed explicitly?
2347 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2348 discardDumpedLayout();
2349 pXmlDoc
= parseLayoutDump();
2350 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/merged", "paraPropsNodeIndex", "12");
2351 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "nType", "PortionType::Para");
2352 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/Text[1]", "Portion", "foar");
2355 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf144057
)
2357 createSwDoc(DATA_DIRECTORY
, "tdf144057.fodt");
2358 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
2359 CPPUNIT_ASSERT(pTextDoc
);
2360 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
2361 SwRootFrame
* pLayout(pDoc
->getIDocumentLayoutAccess().GetCurrentLayout());
2362 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
2363 discardDumpedLayout();
2364 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2365 // show tracked row deletions
2366 assertXPath(pXmlDoc
, "/root/page", 4);
2367 assertXPath(pXmlDoc
, "/root/page[1]/body/tab/row[6]/cell/txt/Text", "Portion", "A6");
2368 assertXPath(pXmlDoc
, "/root/page[2]/body/tab/row[6]/cell/txt/Text", "Portion", "A12");
2369 assertXPath(pXmlDoc
, "/root/page[3]/body/tab/row[6]/cell/txt/Text", "Portion", "B6");
2370 assertXPath(pXmlDoc
, "/root/page[4]/body/tab/row[6]/cell/txt/Text", "Portion", "B12");
2372 // hide tracked table and table row deletions
2373 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
2374 CPPUNIT_ASSERT(pLayout
->IsHideRedlines());
2375 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2376 discardDumpedLayout();
2377 pXmlDoc
= parseLayoutDump();
2379 // This was 4 (unhidden tracked table and table row deletions)
2380 assertXPath(pXmlDoc
, "/root/page", 1);
2381 assertXPath(pXmlDoc
, "/root/page[1]/body/tab", 1);
2382 assertXPath(pXmlDoc
, "/root/page[1]/body/tab/row", 5);
2383 assertXPath(pXmlDoc
, "/root/page[1]/body/tab/row[5]/cell/txt/Text", "Portion", "B12");
2385 // show tracked table and table row deletions again
2386 dispatchCommand(mxComponent
, ".uno:ShowTrackedChanges", {});
2387 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
2388 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2389 discardDumpedLayout();
2390 pXmlDoc
= parseLayoutDump();
2391 assertXPath(pXmlDoc
, "/root/page", 4);
2392 assertXPath(pXmlDoc
, "/root/page[1]/body/tab/row[6]/cell/txt/Text", "Portion", "A6");
2393 assertXPath(pXmlDoc
, "/root/page[2]/body/tab/row[6]/cell/txt/Text", "Portion", "A12");
2394 assertXPath(pXmlDoc
, "/root/page[3]/body/tab/row[6]/cell/txt/Text", "Portion", "B6");
2395 assertXPath(pXmlDoc
, "/root/page[4]/body/tab/row[6]/cell/txt/Text", "Portion", "B12");
2398 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf144347
)
2400 createSwDoc(DATA_DIRECTORY
, "tdf144057.fodt");
2401 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
2402 CPPUNIT_ASSERT(pTextDoc
);
2403 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
2404 SwRootFrame
* pLayout(pDoc
->getIDocumentLayoutAccess().GetCurrentLayout());
2407 dispatchCommand(mxComponent
, ".uno:TrackChanges", {});
2408 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
2409 pDoc
->getIDocumentRedlineAccess().IsRedlineOn());
2410 CPPUNIT_ASSERT(!pLayout
->IsHideRedlines());
2412 // remove first table
2413 SwEditShell
* const pEditShell(pDoc
->GetEditShell());
2414 for (int i
= 0; i
< 12; ++i
)
2415 pEditShell
->AcceptRedline(0);
2417 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2418 discardDumpedLayout();
2419 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2420 // show tracked row deletions
2421 assertXPath(pXmlDoc
, "/root/page", 2);
2422 assertXPath(pXmlDoc
, "/root/page[1]/body/tab", 1);
2424 // select all the text, including the texts before and after the table
2425 // Note: this table contains tracked changes, which was a
2426 // problem for the original OOo implementation of track changes,
2427 // resulting empty tables after accepting the deletion of these tables.
2428 dispatchCommand(mxComponent
, ".uno:SelectAll", {});
2429 dispatchCommand(mxComponent
, ".uno:SelectAll", {});
2430 dispatchCommand(mxComponent
, ".uno:Delete", {});
2431 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2432 discardDumpedLayout();
2433 pXmlDoc
= parseLayoutDump();
2435 // table is deleted with change tracking: it still exists
2436 assertXPath(pXmlDoc
, "/root/page", 2);
2437 assertXPath(pXmlDoc
, "/root/page[1]/body/tab", 1);
2439 // accept all deletions, removing the table completely
2440 while (pEditShell
->GetRedlineCount() > 0)
2441 pEditShell
->AcceptRedline(0);
2443 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2444 discardDumpedLayout();
2445 pXmlDoc
= parseLayoutDump();
2447 assertXPath(pXmlDoc
, "/root/page", 1);
2448 // This was 1 (bad empty table)
2449 assertXPath(pXmlDoc
, "/root/page[1]/body/tab", 0);
2452 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf109137
)
2454 createSwDoc(DATA_DIRECTORY
, "tdf109137.docx");
2455 uno::Reference
<frame::XStorable
> xStorable(mxComponent
, uno::UNO_QUERY
);
2456 utl::TempFile aTempFile
;
2457 aTempFile
.EnableKillingFile();
2458 uno::Sequence
<beans::PropertyValue
> aDescriptor(comphelper::InitPropertySequence({
2459 { "FilterName", uno::Any(OUString("writer8")) },
2461 xStorable
->storeToURL(aTempFile
.GetURL(), aDescriptor
);
2462 loadURL(aTempFile
.GetURL(), "tdf109137.odt");
2463 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2464 // This was 0, the blue rectangle moved from the 1st to the 2nd page.
2465 assertXPath(pXmlDoc
, "/root/page[1]/body/txt/anchored/fly/notxt",
2466 /*nNumberOfNodes=*/1);
2469 //just care it doesn't crash/assert
2470 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint72
)
2472 createSwDoc(DATA_DIRECTORY
, "forcepoint72-1.rtf");
2475 //just care it doesn't crash/assert
2476 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint75
)
2478 createSwDoc(DATA_DIRECTORY
, "forcepoint75-1.rtf");
2481 // FIXME: apparently infinite loop on Mac
2483 //just care it doesn't crash/assert
2484 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testUXTSOREL
)
2486 createSwDoc(DATA_DIRECTORY
, "LIBREOFFICE-UXTSOREL.rtf");
2490 //just care it doesn't crash/assert
2491 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepointFootnoteFrame
)
2493 createSwDoc(DATA_DIRECTORY
, "forcepoint-swfootnoteframe-1.rtf");
2496 //just care it doesn't crash/assert
2497 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint76
)
2499 createSwDoc(DATA_DIRECTORY
, "forcepoint76-1.rtf");
2502 //just care it doesn't crash/assert
2503 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint89
)
2505 createSwWebDoc(DATA_DIRECTORY
, "forcepoint89.html");
2508 //just care it doesn't crash/assert
2509 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint90
)
2511 createSwDoc(DATA_DIRECTORY
, "forcepoint90.rtf");
2514 //just care it doesn't crash/assert
2515 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint91
)
2517 createSwWebDoc(DATA_DIRECTORY
, "forcepoint91.html");
2520 //just care it doesn't crash/assert
2521 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint92
)
2523 createSwDoc(DATA_DIRECTORY
, "forcepoint92.doc");
2526 //just care it doesn't crash/assert
2527 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint93
)
2529 createSwDoc(DATA_DIRECTORY
, "forcepoint93-1.rtf");
2530 createSwDoc(DATA_DIRECTORY
, "forcepoint93-2.rtf");
2533 //just care it doesn't crash/assert
2534 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint94
)
2536 createSwWebDoc(DATA_DIRECTORY
, "forcepoint94.html");
2539 //just care it doesn't crash/assert
2540 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint98
)
2542 createSwWebDoc(DATA_DIRECTORY
, "forcepoint98.html");
2545 //just care it doesn't crash/assert
2546 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint100
)
2548 createSwWebDoc(DATA_DIRECTORY
, "forcepoint100.html");
2551 //just care it doesn't crash/assert
2552 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint102
)
2554 createSwDoc(DATA_DIRECTORY
, "forcepoint102.rtf");
2557 //just care it doesn't crash/assert
2558 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint103
)
2560 createSwWebDoc(DATA_DIRECTORY
, "forcepoint103.html");
2563 //just care it doesn't crash/assert
2564 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf147485Forcepoint
)
2566 createSwDoc(DATA_DIRECTORY
, "tdf147485-forcepoint.doc");
2569 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf118058
)
2571 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf118058.fodt");
2572 // This resulted in a layout loop.
2573 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
2576 //just care it doesn't crash/assert
2577 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testForcepoint99
)
2579 createSwWebDoc(DATA_DIRECTORY
, "forcepoint99.html");
2582 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf128611
)
2584 createSwDoc(DATA_DIRECTORY
, "tdf128611.fodt");
2585 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2586 CPPUNIT_ASSERT(pXmlDoc
);
2587 // Without the accompanying fix in place, this test would have failed with:
2590 // i.e. there were multiple portions in the first paragraph of the A1 cell, which means that the
2591 // rotated text was broken into multiple lines without a good reason.
2592 assertXPath(pXmlDoc
, "//tab/row/cell[1]/txt/Text", "Portion", "Abcd efghijkl");
2595 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf125893
)
2597 createSwDoc(DATA_DIRECTORY
, "tdf125893.docx");
2598 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2599 // This was 400. The paragraph must have zero top border.
2600 assertXPath(pXmlDoc
, "/root/page/body/txt[4]/infos/prtBounds", "top", "0");
2603 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf134463
)
2605 createSwDoc(DATA_DIRECTORY
, "tdf134463.docx");
2606 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2607 // This was 621. The previous paragraph must have zero bottom border.
2608 assertXPath(pXmlDoc
, "/root/page/body/txt[3]/infos/prtBounds", "top", "21");
2611 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf117188
)
2613 createSwDoc(DATA_DIRECTORY
, "tdf117188.docx");
2614 uno::Reference
<frame::XStorable
> xStorable(mxComponent
, uno::UNO_QUERY
);
2615 utl::TempFile aTempFile
;
2616 aTempFile
.EnableKillingFile();
2617 uno::Sequence
<beans::PropertyValue
> aDescriptor(comphelper::InitPropertySequence({
2618 { "FilterName", uno::Any(OUString("writer8")) },
2620 xStorable
->storeToURL(aTempFile
.GetURL(), aDescriptor
);
2621 loadURL(aTempFile
.GetURL(), "tdf117188.odt");
2622 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2623 OUString sWidth
= getXPath(pXmlDoc
, "/root/page/body/txt/anchored/fly/infos/bounds", "width");
2624 OUString sHeight
= getXPath(pXmlDoc
, "/root/page/body/txt/anchored/fly/infos/bounds", "height");
2625 // The text box must have zero border distances
2626 assertXPath(pXmlDoc
, "/root/page/body/txt/anchored/fly/infos/prtBounds", "left", "0");
2627 assertXPath(pXmlDoc
, "/root/page/body/txt/anchored/fly/infos/prtBounds", "top", "0");
2628 assertXPath(pXmlDoc
, "/root/page/body/txt/anchored/fly/infos/prtBounds", "width", sWidth
);
2629 assertXPath(pXmlDoc
, "/root/page/body/txt/anchored/fly/infos/prtBounds", "height", sHeight
);
2632 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf117187
)
2634 createSwDoc(DATA_DIRECTORY
, "tdf117187.odt");
2635 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2637 // there should be no fly portions
2638 assertXPath(pXmlDoc
, "/root/page/body/txt/Special[@nType='PortionType::Fly']", 0);
2641 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf119875
)
2643 createSwDoc(DATA_DIRECTORY
, "tdf119875.odt");
2644 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2646 = getXPath(pXmlDoc
, "/root/page[2]/body/section[1]/infos/bounds", "top").toInt32();
2647 sal_Int32 nSecondTop
2648 = getXPath(pXmlDoc
, "/root/page[2]/body/section[2]/infos/bounds", "top").toInt32();
2649 // The first section had the same top value as the second one, so they
2651 CPPUNIT_ASSERT_LESS(nSecondTop
, nFirstTop
);
2654 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf120287
)
2656 createSwDoc(DATA_DIRECTORY
, "tdf120287.fodt");
2657 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2658 // This was 2, TabOverMargin Word-specific compat flag did not imply
2659 // default-in-Word printer-independent layout, resulting in an additional
2661 assertXPath(pXmlDoc
, "/root/page/body/txt[1]/LineBreak", 1);
2664 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf106234
)
2666 createSwDoc(DATA_DIRECTORY
, "tdf106234.fodt");
2667 // Ensure that all text portions are calculated before testing.
2668 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
2669 CPPUNIT_ASSERT(pTextDoc
);
2670 SwViewShell
* pViewShell
2671 = pTextDoc
->GetDocShell()->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
2672 CPPUNIT_ASSERT(pViewShell
);
2673 pViewShell
->Reformat();
2675 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2676 // In justified paragraphs, there is justification between left tabulators and manual line breaks
2677 assertXPath(pXmlDoc
, "/root/page/body/txt[1]/Special", "nType", "PortionType::Margin");
2678 assertXPathNoAttribute(pXmlDoc
, "/root/page/body/txt[1]/Special", "nWidth");
2679 // but not after centered, right and decimal tabulators
2680 assertXPath(pXmlDoc
, "/root/page/body/txt[2]/Special", "nType", "PortionType::Margin");
2681 // This was a justified line, without nWidth
2682 assertXPath(pXmlDoc
, "/root/page/body/txt[2]/Special", "nWidth", "7881");
2685 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf120287b
)
2687 createSwDoc(DATA_DIRECTORY
, "tdf120287b.fodt");
2688 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2689 // This was 1418, TabOverMargin did the right split of the paragraph to two
2690 // lines, but then calculated a too large tab portion size on the first
2692 assertXPath(pXmlDoc
, "/root/page/body/txt[1]/Text[@nType='PortionType::TabRight']", "nWidth",
2696 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf120287c
)
2698 createSwDoc(DATA_DIRECTORY
, "tdf120287c.fodt");
2699 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2700 // This was 2, the second line was not broken into a 2nd and a 3rd one,
2701 // rendering text outside the paragraph frame.
2702 assertXPath(pXmlDoc
, "/root/page/body/txt[1]/LineBreak", 3);
2705 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf122878
)
2707 createSwDoc(DATA_DIRECTORY
, "tdf122878.docx");
2708 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2709 // FIXME: the XPath should be adjusted when the proper floating table would be imported
2710 const sal_Int32 nTblTop
2711 = getXPath(pXmlDoc
, "/root/page[1]/footer/txt/anchored/fly/tab/infos/bounds", "top")
2713 const sal_Int32 nFirstPageParaCount
2714 = getXPathContent(pXmlDoc
, "count(/root/page[1]/body/txt)").toInt32();
2715 CPPUNIT_ASSERT_EQUAL(sal_Int32(30), nFirstPageParaCount
);
2716 for (sal_Int32 i
= 1; i
<= nFirstPageParaCount
; ++i
)
2718 const OString xPath
= "/root/page[1]/body/txt[" + OString::number(i
) + "]/infos/bounds";
2719 const sal_Int32 nTxtBottom
= getXPath(pXmlDoc
, xPath
.getStr(), "top").toInt32()
2720 + getXPath(pXmlDoc
, xPath
.getStr(), "height").toInt32();
2721 // No body paragraphs should overlap the table in the footer
2722 CPPUNIT_ASSERT_MESSAGE(OString("testing paragraph #" + OString::number(i
)).getStr(),
2723 nTxtBottom
<= nTblTop
);
2727 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf115094
)
2729 createSwDoc(DATA_DIRECTORY
, "tdf115094.docx");
2730 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2733 = getXPath(pXmlDoc
, "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/infos/bounds",
2736 sal_Int32 nTopOfD1Anchored
= getXPath(pXmlDoc
,
2737 "/root/page/body/txt/anchored/fly/tab/row[1]/cell[4]/"
2738 "txt[2]/anchored/fly/infos/bounds",
2741 CPPUNIT_ASSERT_LESS(nTopOfD1Anchored
, nTopOfD1
);
2743 = getXPath(pXmlDoc
, "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/infos/bounds",
2746 sal_Int32 nTopOfB2Anchored
= getXPath(pXmlDoc
,
2747 "/root/page/body/txt/anchored/fly/tab/row[2]/cell[2]/"
2748 "txt[1]/anchored/fly/infos/bounds",
2751 CPPUNIT_ASSERT_LESS(nTopOfB2Anchored
, nTopOfB2
);
2754 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf112290
)
2756 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf112290.docx");
2757 CPPUNIT_ASSERT(pDoc
);
2758 auto pXml
= parseLayoutDump();
2759 assertXPath(pXml
, "/root/page/body/txt/LineBreak[2]", "Line", "Xxxx Xxxx");
2762 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testKeepWithNextPlusFlyFollowTextFlow
)
2764 createSwDoc(DATA_DIRECTORY
, "keep-with-next-fly.fodt");
2767 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2768 // 3 text frames on page 1
2769 assertXPath(pXmlDoc
, "/root/page[1]/body/infos/bounds", "bottom", "7540");
2770 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/infos/bounds", "height", "276");
2771 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/infos/bounds", "height", "276");
2772 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly", 1);
2773 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly/infos/bounds", "top", "1694");
2774 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/infos/bounds", "height", "276");
2775 assertXPath(pXmlDoc
, "/root/page", 1);
2776 discardDumpedLayout();
2779 dispatchCommand(mxComponent
, ".uno:Fieldnames", {});
2780 Scheduler::ProcessEventsToIdle();
2783 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2784 // 1 text frame on page 1, and some empty space
2785 assertXPath(pXmlDoc
, "/root/page[1]/body/infos/bounds", "bottom", "7540");
2786 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/infos/bounds", "height", "5796");
2787 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/infos/bounds", "bottom", "7213");
2788 // 2 text frames on page 2
2789 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/infos/bounds", "height", "276");
2790 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly", 1);
2791 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly/infos/bounds", "top", "10093");
2792 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[2]/infos/bounds", "height", "276");
2793 assertXPath(pXmlDoc
, "/root/page", 2);
2794 discardDumpedLayout();
2797 dispatchCommand(mxComponent
, ".uno:Fieldnames", {});
2798 Scheduler::ProcessEventsToIdle();
2801 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2802 // 3 text frames on page 1
2803 assertXPath(pXmlDoc
, "/root/page[1]/body/infos/bounds", "bottom", "7540");
2804 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/infos/bounds", "height", "276");
2805 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/infos/bounds", "height", "276");
2806 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly", 1);
2807 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[2]/anchored/fly/infos/bounds", "top", "1694");
2808 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[3]/infos/bounds", "height", "276");
2809 assertXPath(pXmlDoc
, "/root/page", 1);
2810 discardDumpedLayout();
2814 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf122607
)
2816 createSwDoc(DATA_DIRECTORY
, "tdf122607.odt");
2817 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2818 assertXPath(pXmlDoc
,
2819 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
2822 assertXPath(pXmlDoc
,
2823 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
2826 assertXPath(pXmlDoc
,
2827 "/root/page[1]/anchored/fly/txt[1]/anchored/fly/tab/row[2]/cell/txt[7]/anchored/"
2832 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf122607_regression
)
2834 discardDumpedLayout();
2835 if (mxComponent
.is())
2836 mxComponent
->dispose();
2838 OUString
const pName("tdf122607_leerzeile.odt");
2840 OUString
const url(m_directories
.getURLFromSrc(DATA_DIRECTORY
) + pName
);
2842 // note: must set Hidden property, so that SfxFrameViewWindow_Impl::Resize()
2843 // does *not* forward initial VCL Window Resize and thereby triggers a
2844 // layout which does not happen on soffice --convert-to pdf.
2845 std::vector
<beans::PropertyValue
> aFilterOptions
= {
2846 { beans::PropertyValue("Hidden", -1, uno::Any(true), beans::PropertyState_DIRECT_VALUE
) },
2849 std::cout
<< pName
<< ":\n";
2851 // inline the loading because currently properties can't be passed...
2852 mxComponent
= loadFromDesktop(url
, "com.sun.star.text.TextDocument",
2853 comphelper::containerToSequence(aFilterOptions
));
2854 uno::Sequence
<beans::PropertyValue
> props(comphelper::InitPropertySequence({
2855 { "FilterName", uno::Any(OUString("writer_pdf_Export")) },
2857 utl::TempFile aTempFile
;
2858 uno::Reference
<frame::XStorable
> xStorable(mxComponent
, uno::UNO_QUERY
);
2859 xStorable
->storeToURL(aTempFile
.GetURL(), props
);
2861 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
2862 // somehow these 2 rows overlapped in the PDF unless CalcLayout() runs
2863 assertXPath(pXmlDoc
, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "mbFixSize",
2865 assertXPath(pXmlDoc
, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "top", "2977");
2866 assertXPath(pXmlDoc
, "/root/page[1]/anchored/fly/tab[1]/row[1]/infos/bounds", "height", "241");
2867 assertXPath(pXmlDoc
, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "mbFixSize",
2869 // this was 3034, causing the overlap
2870 assertXPath(pXmlDoc
, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "top", "3218");
2871 assertXPath(pXmlDoc
, "/root/page[1]/anchored/fly/tab[1]/row[2]/infos/bounds", "height", "164");
2873 aTempFile
.EnableKillingFile();
2876 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testBtlrCell
)
2878 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "btlr-cell.odt");
2879 SwDocShell
* pShell
= pDoc
->GetDocShell();
2881 // Dump the rendering of the first page as an XML file.
2882 std::shared_ptr
<GDIMetaFile
> xMetaFile
= pShell
->GetPreviewMetaFile();
2883 MetafileXmlDump dumper
;
2884 xmlDocUniquePtr pXmlDoc
= dumpAndParse(dumper
, *xMetaFile
);
2885 CPPUNIT_ASSERT(pXmlDoc
);
2887 // Without the accompanying fix in place, this test would have failed, as
2888 // the orientation was 0 (layout did not take btlr direction request from
2890 assertXPath(pXmlDoc
, "//font[1]", "orientation", "900");
2892 #if !defined(MACOSX) && !defined(_WIN32) // macOS fails with x == 2662 for some reason.
2893 // Without the accompanying fix in place, this test would have failed with 'Expected: 1915;
2894 // Actual : 1756', i.e. the AAA1 text was too close to the left cell border due to an ascent vs
2895 // descent mismatch when calculating the baseline offset of the text portion.
2896 assertXPath(pXmlDoc
, "//textarray[1]", "x", "1915");
2897 assertXPath(pXmlDoc
, "//textarray[1]", "y", "2707");
2899 // Without the accompanying fix in place, this test would have failed with 'Expected: 1979;
2900 // Actual : 2129', i.e. the gray background of the "AAA2." text was too close to the right edge
2901 // of the text portion. Now it's exactly behind the text portion.
2902 assertXPath(pXmlDoc
, "//rect[@top='2159']", "left", "1979");
2904 // Without the accompanying fix in place, this test would have failed with 'Expected: 269;
2905 // Actual : 0', i.e. the AAA2 frame was not visible due to 0 width.
2906 pXmlDoc
= parseLayoutDump();
2907 assertXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width", "269");
2909 // Test the position of the cursor after doc load.
2910 // We expect that it's inside the first text frame in the first cell.
2911 // More precisely, this is a bottom to top vertical frame, so we expect it's at the start, which
2912 // means it's at the lower half of the text frame rectangle (vertically).
2913 SwWrtShell
* pWrtShell
= pShell
->GetWrtShell();
2914 CPPUNIT_ASSERT(pWrtShell
);
2916 const SwRect
& rCharRect
= pWrtShell
->GetCharRect();
2917 SwTwips nFirstParaTop
2918 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "top").toInt32();
2919 SwTwips nFirstParaHeight
2920 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/txt[1]/infos/bounds", "height")
2922 SwTwips nFirstParaMiddle
= nFirstParaTop
+ nFirstParaHeight
/ 2;
2923 SwTwips nFirstParaBottom
= nFirstParaTop
+ nFirstParaHeight
;
2924 // Without the accompanying fix in place, this test would have failed: the lower half (vertical)
2925 // range was 2273 -> 2835, the good vertical position is 2730, the bad one was 1830.
2926 CPPUNIT_ASSERT_GREATER(nFirstParaMiddle
, rCharRect
.Top());
2927 CPPUNIT_ASSERT_LESS(nFirstParaBottom
, rCharRect
.Top());
2929 // Save initial cursor position.
2930 SwPosition aCellStart
= *pWrtShell
->GetCursor()->Start();
2932 // Test that pressing "up" at the start of the cell goes to the next character position.
2933 SwNodeOffset nNodeIndex
= pWrtShell
->GetCursor()->Start()->nNode
.GetIndex();
2934 sal_Int32 nIndex
= pWrtShell
->GetCursor()->Start()->nContent
.GetIndex();
2935 KeyEvent
aKeyEvent(0, KEY_UP
);
2936 SwEditWin
& rEditWin
= pShell
->GetView()->GetEditWin();
2937 rEditWin
.KeyInput(aKeyEvent
);
2938 Scheduler::ProcessEventsToIdle();
2939 // Without the accompanying fix in place, this test would have failed: "up" was interpreted as
2940 // logical "left", which does nothing if you're at the start of the text anyway.
2941 CPPUNIT_ASSERT_EQUAL(nIndex
+ 1, pWrtShell
->GetCursor()->Start()->nContent
.GetIndex());
2943 // Test that pressing "right" goes to the next paragraph (logical "down").
2944 sal_Int32 nContentIndex
= pWrtShell
->GetCursor()->Start()->nContent
.GetIndex();
2945 aKeyEvent
= KeyEvent(0, KEY_RIGHT
);
2946 rEditWin
.KeyInput(aKeyEvent
);
2947 Scheduler::ProcessEventsToIdle();
2948 // Without the accompanying fix in place, this test would have failed: the cursor went to the
2949 // paragraph after the table.
2950 CPPUNIT_ASSERT_EQUAL(nNodeIndex
+ 1, pWrtShell
->GetCursor()->Start()->nNode
.GetIndex());
2952 // Test that we have the correct character index after traveling to the next paragraph.
2953 // Without the accompanying fix in place, this test would have failed: char position was 5, i.e.
2954 // the cursor jumped to the end of the paragraph for no reason.
2955 CPPUNIT_ASSERT_EQUAL(nContentIndex
, pWrtShell
->GetCursor()->Start()->nContent
.GetIndex());
2957 // Test that clicking "below" the second paragraph positions the cursor at the start of the
2958 // second paragraph.
2959 SwRootFrame
* pLayout
= pDoc
->getIDocumentLayoutAccess().GetCurrentLayout();
2960 SwPosition
aPosition(aCellStart
);
2961 SwTwips nSecondParaLeft
2962 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "left")
2964 SwTwips nSecondParaWidth
2965 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "width")
2967 SwTwips nSecondParaTop
2968 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "top").toInt32();
2969 SwTwips nSecondParaHeight
2970 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/txt[2]/infos/bounds", "height")
2973 aPoint
.setX(nSecondParaLeft
+ nSecondParaWidth
/ 2);
2974 aPoint
.setY(nSecondParaTop
+ nSecondParaHeight
- 100);
2975 SwCursorMoveState
aState(CursorMoveState::NONE
);
2976 pLayout
->GetModelPositionForViewPoint(&aPosition
, aPoint
, &aState
);
2977 CPPUNIT_ASSERT_EQUAL(aCellStart
.nNode
.GetIndex() + 1, aPosition
.nNode
.GetIndex());
2978 // Without the accompanying fix in place, this test would have failed: character position was 5,
2979 // i.e. cursor was at the end of the paragraph.
2980 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aPosition
.nContent
.GetIndex());
2982 // Test that the selection rectangles are inside the cell frame if we select all the cell
2985 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/infos/bounds", "left").toInt32();
2987 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/infos/bounds", "width").toInt32();
2989 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/infos/bounds", "top").toInt32();
2991 = getXPath(pXmlDoc
, "/root/page/body/tab/row/cell[1]/infos/bounds", "height").toInt32();
2992 SwRect
aCellRect(Point(nCellLeft
, nCellTop
), Size(nCellWidth
, nCellHeight
));
2993 pWrtShell
->SelAll();
2994 SwShellCursor
* pShellCursor
= pWrtShell
->getShellCursor(/*bBlock=*/false);
2995 CPPUNIT_ASSERT(!pShellCursor
->empty());
2996 // Without the accompanying fix in place, this test would have failed with:
2997 // selection rectangle 269x2573@(1970,2172) is not inside cell rectangle 3207x1134@(1593,1701)
2998 // i.e. the selection went past the bottom border of the cell frame.
2999 for (const auto& rRect
: *pShellCursor
)
3001 std::stringstream ss
;
3002 ss
<< "selection rectangle " << rRect
<< " is not inside cell rectangle " << aCellRect
;
3003 CPPUNIT_ASSERT_MESSAGE(ss
.str(), aCellRect
.Contains(rRect
));
3006 // Make sure that the correct rectangle gets repainted on scroll.
3007 SwFrame
* pPageFrame
= pLayout
->GetLower();
3008 CPPUNIT_ASSERT(pPageFrame
->IsPageFrame());
3010 SwFrame
* pBodyFrame
= pPageFrame
->GetLower();
3011 CPPUNIT_ASSERT(pBodyFrame
->IsBodyFrame());
3013 SwFrame
* pTabFrame
= pBodyFrame
->GetLower();
3014 CPPUNIT_ASSERT(pTabFrame
->IsTabFrame());
3016 SwFrame
* pRowFrame
= pTabFrame
->GetLower();
3017 CPPUNIT_ASSERT(pRowFrame
->IsRowFrame());
3019 SwFrame
* pCellFrame
= pRowFrame
->GetLower();
3020 CPPUNIT_ASSERT(pCellFrame
->IsCellFrame());
3022 SwFrame
* pFrame
= pCellFrame
->GetLower();
3023 CPPUNIT_ASSERT(pFrame
->IsTextFrame());
3025 SwTextFrame
* pTextFrame
= static_cast<SwTextFrame
*>(pFrame
);
3026 pTextFrame
->SwapWidthAndHeight();
3027 // Mimic what normally SwTextFrame::PaintSwFrame() does:
3028 SwRect
aRect(4207, 2273, 269, 572);
3029 pTextFrame
->SwitchVerticalToHorizontal(aRect
);
3030 // Without the accompanying fix in place, this test would have failed with:
3031 // Expected: 572x269@(1691,4217)
3032 // Actual : 572x269@(2263,4217)
3033 // i.e. the paint rectangle position was incorrect, text was not painted on scrolling up.
3034 CPPUNIT_ASSERT_EQUAL(SwRect(1691, 4217, 572, 269), aRect
);
3038 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf123898
)
3040 createSwDoc(DATA_DIRECTORY
, "tdf123898.odt");
3042 // Make sure spellchecker has done its job already
3043 Scheduler::ProcessEventsToIdle();
3045 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3046 // Make sure that the arrow on the left is not there (there are 44 children if it's there)
3047 assertXPathChildren(pXmlDoc
, "/root/page/body/txt/anchored/fly/txt", 43);
3050 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf123651
)
3052 createSwDoc(DATA_DIRECTORY
, "tdf123651.docx");
3053 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3054 // Without the accompanying fix in place, this test would have failed with 'Expected: 7639;
3055 // Actual: 12926'. The shape was below the second "Lorem ipsum" text, not above it.
3056 const sal_Int32 nTopValue
3057 = getXPath(pXmlDoc
, "//anchored/SwAnchoredDrawObject/bounds", "top").toInt32();
3058 CPPUNIT_ASSERT_DOUBLES_EQUAL(7639, nTopValue
, 10);
3061 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf116501
)
3063 //just care it doesn't freeze
3064 createSwDoc(DATA_DIRECTORY
, "tdf116501.odt");
3067 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testAbi11870
)
3069 //just care it doesn't assert
3070 createSwDoc(DATA_DIRECTORY
, "abi11870-2.odt");
3073 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf118719
)
3075 // Insert a page break.
3076 SwDoc
* pDoc
= createSwDoc();
3077 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
3079 // Enable hide whitespace mode.
3080 SwViewOption
aViewOptions(*pWrtShell
->GetViewOptions());
3081 aViewOptions
.SetHideWhitespaceMode(true);
3082 pWrtShell
->ApplyViewOptions(aViewOptions
);
3084 pWrtShell
->Insert("first");
3085 pWrtShell
->InsertPageBreak();
3086 pWrtShell
->Insert("second");
3088 // Without the accompanying fix in place, this test would have failed, as the height of the
3089 // first page was 15840 twips, instead of the much smaller 276.
3090 sal_Int32 nOther
= parseDump("/root/page[1]/infos/bounds", "height").toInt32();
3091 sal_Int32 nLast
= parseDump("/root/page[2]/infos/bounds", "height").toInt32();
3092 CPPUNIT_ASSERT_GREATER(nOther
, nLast
);
3095 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTabOverMargin
)
3097 createSwDoc(DATA_DIRECTORY
, "tab-over-margin.odt");
3098 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3100 // 2nd paragraph has a tab over the right margin, and with the TabOverMargin compat option,
3101 // there is enough space to have all content in a single line.
3102 // Without the accompanying fix in place, this test would have failed, there were 2 lines.
3103 assertXPath(pXmlDoc
, "/root/page/body/txt[2]/LineBreak", 1);
3106 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testImageComment
)
3108 // Load a document that has "aaa" in it, then a commented image (4th char is the as-char image,
3109 // 5th char is the comment anchor).
3110 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "image-comment.odt");
3111 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
3113 // Look up a layout position which is on the right of the image.
3114 SwRootFrame
* pRoot
= pWrtShell
->GetLayout();
3115 CPPUNIT_ASSERT(pRoot
->GetLower()->IsPageFrame());
3116 SwPageFrame
* pPage
= static_cast<SwPageFrame
*>(pRoot
->GetLower());
3117 CPPUNIT_ASSERT(pPage
->GetLower()->IsBodyFrame());
3118 SwBodyFrame
* pBody
= static_cast<SwBodyFrame
*>(pPage
->GetLower());
3119 CPPUNIT_ASSERT(pBody
->GetLower()->IsTextFrame());
3120 SwTextFrame
* pTextFrame
= static_cast<SwTextFrame
*>(pBody
->GetLower());
3121 CPPUNIT_ASSERT(pTextFrame
->GetDrawObjs());
3122 SwSortedObjs
& rDrawObjs
= *pTextFrame
->GetDrawObjs();
3123 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rDrawObjs
.size());
3124 SwAnchoredObject
* pDrawObj
= rDrawObjs
[0];
3125 const SwRect
& rDrawObjRect
= pDrawObj
->GetObjRect();
3126 Point aPoint
= rDrawObjRect
.Center();
3127 aPoint
.setX(aPoint
.getX() + rDrawObjRect
.Width() / 2);
3129 // Ask for the doc model pos of this layout point.
3130 SwPosition
aPosition(*pTextFrame
->GetTextNodeForFirstText());
3131 pTextFrame
->GetModelPositionForViewPoint(&aPosition
, aPoint
);
3133 // Without the accompanying fix in place, this test would have failed with:
3136 // i.e. the cursor got positioned between the image and its comment, so typing extended the
3137 // comment, instead of adding content after the commented image.
3138 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(5), aPosition
.nContent
.GetIndex());
3141 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testScriptField
)
3143 // Test clicking script field inside table ( tdf#141079 )
3144 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf141079.odt");
3145 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
3147 // Look up layout position which is the first cell in the table
3148 SwRootFrame
* pRoot
= pWrtShell
->GetLayout();
3149 CPPUNIT_ASSERT(pRoot
->GetLower()->IsPageFrame());
3150 SwPageFrame
* pPage
= static_cast<SwPageFrame
*>(pRoot
->GetLower());
3151 CPPUNIT_ASSERT(pPage
->GetLower()->IsBodyFrame());
3152 SwBodyFrame
* pBody
= static_cast<SwBodyFrame
*>(pPage
->GetLower());
3153 CPPUNIT_ASSERT(pBody
->GetLower()->IsTextFrame());
3154 SwTextFrame
* pTextFrame
= static_cast<SwTextFrame
*>(pBody
->GetLower());
3155 CPPUNIT_ASSERT(pTextFrame
->GetNext()->IsTabFrame());
3156 SwFrame
* pTable
= pTextFrame
->GetNext();
3157 SwFrame
* pRow1
= pTable
->GetLower();
3158 CPPUNIT_ASSERT(pRow1
->GetLower()->IsCellFrame());
3159 SwFrame
* pCell1
= pRow1
->GetLower();
3160 CPPUNIT_ASSERT(pCell1
->GetLower()->IsTextFrame());
3161 SwTextFrame
* pCellTextFrame
= static_cast<SwTextFrame
*>(pCell1
->GetLower());
3162 const SwRect
& rCellRect
= pCell1
->getFrameArea();
3163 Point aPoint
= rCellRect
.Center();
3164 aPoint
.setX(aPoint
.getX() - rCellRect
.Width() / 2);
3166 // Ask for the doc model pos of this layout point.
3167 SwPosition
aPosition(*pCellTextFrame
->GetTextNodeForFirstText());
3168 pCellTextFrame
->GetModelPositionForViewPoint(&aPosition
, aPoint
);
3170 // Position was 1 without the fix from tdf#141079
3171 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(0), aPosition
.nContent
.GetIndex());
3174 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testCommentCursorPosition
)
3176 // Load a document that has "aaa" in it, followed by three comments.
3177 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "endOfLineComments.odt");
3178 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
3180 SwRootFrame
* pRoot
= pWrtShell
->GetLayout();
3181 CPPUNIT_ASSERT(pRoot
->GetLower()->IsPageFrame());
3182 SwPageFrame
* pPage
= static_cast<SwPageFrame
*>(pRoot
->GetLower());
3183 CPPUNIT_ASSERT(pPage
->GetLower()->IsBodyFrame());
3184 SwBodyFrame
* pBody
= static_cast<SwBodyFrame
*>(pPage
->GetLower());
3185 CPPUNIT_ASSERT(pBody
->GetLower()->IsTextFrame());
3186 SwTextFrame
* pTextFrame
= static_cast<SwTextFrame
*>(pBody
->GetLower());
3188 // Set a point in the whitespace past the end of the first line.
3189 Point aPoint
= pWrtShell
->getShellCursor(false)->GetSttPos();
3190 aPoint
.setX(aPoint
.getX() + 10000);
3192 // Ask for the doc model pos of this layout point.
3193 SwPosition
aPosition(*pTextFrame
->GetTextNodeForFirstText());
3194 pTextFrame
->GetModelPositionForViewPoint(&aPosition
, aPoint
);
3196 // Without the accompanying fix in place, this test would have failed with:
3198 // - Actual : 3 or 4
3199 // i.e. the cursor got positioned before the comments,
3200 // so typing extended the first comment instead of adding content after the comments.
3201 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(6), aPosition
.nContent
.GetIndex());
3202 // The second line is also important, but can't be auto-tested
3203 // since the failing situation depends on GetViewWidth which is zero in the headless tests.
3204 // bb<comment>| - the cursor should move behind the |, not before it.
3207 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testCombiningCharacterCursorPosition
)
3209 // Load a document that has "a" in it, followed by a combining acute in a separate rext span
3210 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf138592-a-acute.fodt");
3211 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
3213 SwRootFrame
* pRoot
= pWrtShell
->GetLayout();
3214 CPPUNIT_ASSERT(pRoot
->GetLower()->IsPageFrame());
3215 SwPageFrame
* pPage
= static_cast<SwPageFrame
*>(pRoot
->GetLower());
3216 CPPUNIT_ASSERT(pPage
->GetLower()->IsBodyFrame());
3217 SwBodyFrame
* pBody
= static_cast<SwBodyFrame
*>(pPage
->GetLower());
3218 CPPUNIT_ASSERT(pBody
->GetLower()->IsTextFrame());
3219 SwTextFrame
* pTextFrame
= static_cast<SwTextFrame
*>(pBody
->GetLower());
3221 // Set a point in the whitespace past the end of the first line.
3222 Point aPoint
= pWrtShell
->getShellCursor(false)->GetSttPos();
3223 aPoint
.AdjustX(10000);
3225 // Ask for the doc model pos of this layout point.
3226 SwPosition
aPosition(*pTextFrame
->GetTextNodeForFirstText());
3227 pTextFrame
->GetModelPositionForViewPoint(&aPosition
, aPoint
);
3229 // Without the accompanying fix in place, this test would have failed with:
3232 // i.e. the cursor got positioned before the acute, so typing shifted the acute (applying it
3233 // to newly typed characters) instead of adding content after it.
3234 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), aPosition
.nContent
.GetIndex());
3237 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf64222
)
3239 createSwDoc(DATA_DIRECTORY
, "tdf64222.docx");
3240 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3241 assertXPath(pXmlDoc
, "/root/page/body/txt[2]/Special", "nHeight", "560");
3244 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf113014
)
3246 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf113014.fodt");
3247 SwDocShell
* pShell
= pDoc
->GetDocShell();
3249 // Dump the rendering of the first page as an XML file.
3250 std::shared_ptr
<GDIMetaFile
> xMetaFile
= pShell
->GetPreviewMetaFile();
3251 MetafileXmlDump dumper
;
3252 xmlDocUniquePtr pXmlDoc
= dumpAndParse(dumper
, *xMetaFile
);
3253 CPPUNIT_ASSERT(pXmlDoc
);
3255 // This failed, if numbering of cell A1 is missing
3256 // (A1: left indent: 3 cm, first line indent: -3 cm
3257 // A2: left indent: 0 cm, first line indent: 0 cm)
3258 assertXPathContent(pXmlDoc
, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "1.");
3259 assertXPathContent(pXmlDoc
, "/metafile/push[1]/push[1]/push[1]/textarray[3]/text", "2.");
3260 assertXPathContent(pXmlDoc
, "/metafile/push[1]/push[1]/push[1]/textarray[5]/text", "3.");
3263 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf130218
)
3265 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf130218.fodt");
3266 SwDocShell
* pShell
= pDoc
->GetDocShell();
3268 // Dump the rendering of the first page as an XML file.
3269 std::shared_ptr
<GDIMetaFile
> xMetaFile
= pShell
->GetPreviewMetaFile();
3270 MetafileXmlDump dumper
;
3272 xmlDocUniquePtr pXmlDoc
= dumpAndParse(dumper
, *xMetaFile
);
3273 CPPUNIT_ASSERT(pXmlDoc
);
3275 // This failed, if hanging first line was hidden
3276 assertXPathContent(pXmlDoc
, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "Text");
3279 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf127235
)
3281 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf127235.odt");
3282 // This resulted in a layout loop.
3283 pDoc
->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
3286 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf138039
)
3288 createSwDoc(DATA_DIRECTORY
, "tdf138039.odt");
3290 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3292 // there are 3 pages
3293 assertXPath(pXmlDoc
, "/root/page", 3);
3294 // table on first page
3295 assertXPath(pXmlDoc
, "/root/page[1]/body/tab", 1);
3296 assertXPath(pXmlDoc
, "/root/page[1]/body/txt", 0);
3297 // paragraph with large fly on second page
3298 assertXPath(pXmlDoc
, "/root/page[2]/body/tab", 0);
3299 assertXPath(pXmlDoc
, "/root/page[2]/body/txt", 1);
3300 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly", 1);
3301 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top", "17915");
3302 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "height",
3304 // paragraph on third page
3305 assertXPath(pXmlDoc
, "/root/page[3]/body/tab", 0);
3306 assertXPath(pXmlDoc
, "/root/page[3]/body/txt", 1);
3307 assertXPath(pXmlDoc
, "/root/page[3]/body/txt[1]/anchored", 0);
3310 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf134298
)
3312 createSwDoc(DATA_DIRECTORY
, "tdf134298.ott");
3314 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3316 // there are 2 pages
3317 assertXPath(pXmlDoc
, "/root/page", 2);
3318 // table and first para on first page
3319 assertXPath(pXmlDoc
, "/root/page[1]/body/tab", 1);
3320 assertXPath(pXmlDoc
, "/root/page[1]/body/txt", 1);
3321 assertXPath(pXmlDoc
, "/root/page[1]/body/txt[1]/anchored", 0);
3322 // paragraph with large fly on second page
3323 assertXPath(pXmlDoc
, "/root/page[2]/body/tab", 0);
3324 assertXPath(pXmlDoc
, "/root/page[2]/body/txt", 1);
3325 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly", 1);
3326 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "top", "17897");
3327 assertXPath(pXmlDoc
, "/root/page[2]/body/txt[1]/anchored/fly[1]/infos/bounds", "height",
3331 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testShapeAllowOverlap
)
3333 // Need to find out why this fails on macOS and why this is unstable on Windows.
3334 #if !defined(MACOSX) && !defined(_WIN32)
3335 // Create an empty document with two, intentionally overlapping shapes.
3336 // Set their AllowOverlap property to false.
3337 loadURL("private:factory/swriter", nullptr);
3338 uno::Reference
<lang::XMultiServiceFactory
> xDocument(mxComponent
, uno::UNO_QUERY
);
3339 awt::Point
aPoint(1000, 1000);
3340 awt::Size
aSize(2000, 2000);
3341 uno::Reference
<drawing::XShape
> xShape(
3342 xDocument
->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY
);
3343 xShape
->setPosition(aPoint
);
3344 xShape
->setSize(aSize
);
3345 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(xDocument
, uno::UNO_QUERY
);
3346 uno::Reference
<beans::XPropertySet
> xShapeProperties(xShape
, uno::UNO_QUERY
);
3347 xShapeProperties
->setPropertyValue("AllowOverlap", uno::makeAny(false));
3348 xShapeProperties
->setPropertyValue("AnchorType",
3349 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER
));
3350 xDrawPageSupplier
->getDrawPage()->add(xShape
);
3352 aPoint
= awt::Point(2000, 2000);
3353 xShape
.set(xDocument
->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY
);
3354 xShape
->setPosition(aPoint
);
3355 xShape
->setSize(aSize
);
3356 xShapeProperties
.set(xShape
, uno::UNO_QUERY
);
3357 xShapeProperties
->setPropertyValue("AllowOverlap", uno::makeAny(false));
3358 xShapeProperties
->setPropertyValue("AnchorType",
3359 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER
));
3360 xDrawPageSupplier
->getDrawPage()->add(xShape
);
3362 // Now verify that the rectangle of the anchored objects don't overlap.
3363 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
3364 CPPUNIT_ASSERT(pTextDoc
);
3365 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
3366 SwRootFrame
* pLayout
= pDoc
->getIDocumentLayoutAccess().GetCurrentLayout();
3367 SwFrame
* pPageFrame
= pLayout
->GetLower();
3368 SwFrame
* pBodyFrame
= pPageFrame
->GetLower();
3369 SwFrame
* pTextFrame
= pBodyFrame
->GetLower();
3370 CPPUNIT_ASSERT(pTextFrame
->GetDrawObjs());
3371 SwSortedObjs
& rObjs
= *pTextFrame
->GetDrawObjs();
3372 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs
.size());
3373 SwAnchoredObject
* pFirst
= rObjs
[0];
3374 SwAnchoredObject
* pSecond
= rObjs
[1];
3375 // Without the accompanying fix in place, this test would have failed: the layout dump was
3376 // <bounds left="1984" top="1984" width="1137" height="1137"/>
3377 // <bounds left="2551" top="2551" width="1137" height="1137"/>
3378 // so there was a clear vertical overlap. (Allow for 1px tolerance.)
3379 OString aMessage
= "Unexpected overlap: first shape's bottom is "
3380 + OString::number(pFirst
->GetObjRect().Bottom()) + ", second shape's top is "
3381 + OString::number(pSecond
->GetObjRect().Top());
3382 CPPUNIT_ASSERT_MESSAGE(aMessage
.getStr(),
3383 std::abs(pFirst
->GetObjRect().Bottom() - pSecond
->GetObjRect().Top())
3388 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testShapeAllowOverlapWrap
)
3390 // Create an empty document with two, intentionally overlapping shapes.
3391 // Set their AllowOverlap property to false and their wrap to through.
3392 loadURL("private:factory/swriter", nullptr);
3393 uno::Reference
<lang::XMultiServiceFactory
> xDocument(mxComponent
, uno::UNO_QUERY
);
3394 awt::Point
aPoint(1000, 1000);
3395 awt::Size
aSize(2000, 2000);
3396 uno::Reference
<drawing::XShape
> xShape(
3397 xDocument
->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY
);
3398 xShape
->setPosition(aPoint
);
3399 xShape
->setSize(aSize
);
3400 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(xDocument
, uno::UNO_QUERY
);
3401 uno::Reference
<beans::XPropertySet
> xShapeProperties(xShape
, uno::UNO_QUERY
);
3402 xShapeProperties
->setPropertyValue("AllowOverlap", uno::makeAny(false));
3403 xShapeProperties
->setPropertyValue("AnchorType",
3404 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER
));
3405 xShapeProperties
->setPropertyValue("Surround", uno::makeAny(text::WrapTextMode_THROUGH
));
3406 xDrawPageSupplier
->getDrawPage()->add(xShape
);
3408 aPoint
= awt::Point(2000, 2000);
3409 xShape
.set(xDocument
->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY
);
3410 xShape
->setPosition(aPoint
);
3411 xShape
->setSize(aSize
);
3412 xShapeProperties
.set(xShape
, uno::UNO_QUERY
);
3413 xShapeProperties
->setPropertyValue("AllowOverlap", uno::makeAny(false));
3414 xShapeProperties
->setPropertyValue("AnchorType",
3415 uno::makeAny(text::TextContentAnchorType_AT_CHARACTER
));
3416 xShapeProperties
->setPropertyValue("Surround", uno::makeAny(text::WrapTextMode_THROUGH
));
3417 xDrawPageSupplier
->getDrawPage()->add(xShape
);
3419 // Now verify that the rectangle of the anchored objects do overlap.
3420 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
3421 CPPUNIT_ASSERT(pTextDoc
);
3422 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
3423 SwRootFrame
* pLayout
= pDoc
->getIDocumentLayoutAccess().GetCurrentLayout();
3424 SwFrame
* pPageFrame
= pLayout
->GetLower();
3425 SwFrame
* pBodyFrame
= pPageFrame
->GetLower();
3426 SwFrame
* pTextFrame
= pBodyFrame
->GetLower();
3427 CPPUNIT_ASSERT(pTextFrame
->GetDrawObjs());
3428 SwSortedObjs
& rObjs
= *pTextFrame
->GetDrawObjs();
3429 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rObjs
.size());
3430 SwAnchoredObject
* pFirst
= rObjs
[0];
3431 SwAnchoredObject
* pSecond
= rObjs
[1];
3432 // Without the accompanying fix in place, this test would have failed: AllowOverlap=no had
3433 // priority over Surround=through (which is bad for Word compat).
3434 CPPUNIT_ASSERT(pSecond
->GetObjRect().Overlaps(pFirst
->GetObjRect()));
3437 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf124600
)
3439 createSwDoc(DATA_DIRECTORY
, "tdf124600.docx");
3440 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3442 // Without the accompanying fix in place, this test would have failed with:
3445 // i.e. the last line in the body text had 2 lines, while it should have 1, as Word does (as the
3446 // fly frame does not intersect with the print area of the paragraph.)
3447 assertXPath(pXmlDoc
, "/root/page/body/txt[2]/LineBreak", 1);
3450 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf124601
)
3452 // This is a testcase for the ContinuousEndnotes compat flag.
3453 // The document has 2 pages, the endnote anchor is on the first page.
3454 // The endnote should be on the 2nd page together with the last page content.
3455 createSwDoc(DATA_DIRECTORY
, "tdf124601.doc");
3456 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3458 // Without the accompanying fix in place, this test would have failed with:
3461 // i.e. there was a separate endnote page, even when the ContinuousEndnotes compat option was
3463 assertXPath(pXmlDoc
, "/root/page", 2);
3464 assertXPath(pXmlDoc
, "/root/page[2]/ftncont", 1);
3467 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf124601b
)
3469 // Table has an image, which is anchored in the first row, but its vertical position is large
3470 // enough to be rendered in the second row.
3471 // The shape has layoutInCell=1, so should match what Word does here.
3472 // Also the horizontal position should be in the last column, even if the anchor is in the
3473 // last-but-one column.
3474 createSwDoc(DATA_DIRECTORY
, "tdf124601b.doc");
3475 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3477 sal_Int32 nFlyTop
= getXPath(pXmlDoc
, "//anchored/fly/infos/bounds", "top").toInt32();
3478 sal_Int32 nFlyLeft
= getXPath(pXmlDoc
, "//anchored/fly/infos/bounds", "left").toInt32();
3480 = nFlyLeft
+ getXPath(pXmlDoc
, "//anchored/fly/infos/bounds", "width").toInt32();
3481 sal_Int32 nSecondRowTop
= getXPath(pXmlDoc
, "//tab/row[2]/infos/bounds", "top").toInt32();
3482 sal_Int32 nLastCellLeft
3483 = getXPath(pXmlDoc
, "//tab/row[1]/cell[5]/infos/bounds", "left").toInt32();
3484 sal_Int32 nLastCellRight
3485 = nLastCellLeft
+ getXPath(pXmlDoc
, "//tab/row[1]/cell[5]/infos/bounds", "width").toInt32();
3486 // Without the accompanying fix in place, this test would have failed with:
3487 // - Expected greater than: 3736
3489 // i.e. the image was still inside the first row.
3490 CPPUNIT_ASSERT_GREATER(nSecondRowTop
, nFlyTop
);
3492 // Without the accompanying fix in place, this test would have failed with:
3493 // - Expected greater than: 9640
3495 // i.e. the right edge of the image was not within the bounds of the last column, the right edge
3496 // was in the last-but-one column.
3497 CPPUNIT_ASSERT_GREATER(nLastCellLeft
, nFlyRight
);
3498 CPPUNIT_ASSERT_LESS(nLastCellRight
, nFlyRight
);
3501 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf124770
)
3503 // Enable content over margin.
3504 SwDoc
* pDoc
= createSwDoc();
3505 pDoc
->getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN
, true);
3508 SwPageDesc
& rPageDesc
= pDoc
->GetPageDesc(0);
3509 SwFrameFormat
& rPageFormat
= rPageDesc
.GetMaster();
3510 const SwAttrSet
& rPageSet
= rPageFormat
.GetAttrSet();
3511 SwFormatFrameSize aPageSize
= rPageSet
.GetFrameSize();
3512 aPageSize
.SetWidth(3703);
3513 rPageFormat
.SetFormatAttr(aPageSize
);
3515 // Set left and right margin.
3516 SvxLRSpaceItem aLRSpace
= rPageSet
.GetLRSpace();
3517 aLRSpace
.SetLeft(1418);
3518 aLRSpace
.SetRight(1418);
3519 rPageFormat
.SetFormatAttr(aLRSpace
);
3520 pDoc
->ChgPageDesc(0, rPageDesc
);
3522 // Set font to italic 20pt Liberation Serif.
3523 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
3524 SfxItemSet
aTextSet(pWrtShell
->GetView().GetPool(),
3525 svl::Items
<RES_CHRATR_BEGIN
, RES_CHRATR_END
- 1>);
3526 SvxFontItem
aFont(RES_CHRATR_FONT
);
3527 aFont
.SetFamilyName("Liberation Serif");
3528 aTextSet
.Put(aFont
);
3529 SvxFontHeightItem
aHeight(400, 100, RES_CHRATR_FONTSIZE
);
3530 aTextSet
.Put(aHeight
);
3531 SvxPostureItem
aItalic(ITALIC_NORMAL
, RES_CHRATR_POSTURE
);
3532 aTextSet
.Put(aItalic
);
3533 pWrtShell
->SetAttrSet(aTextSet
);
3536 pWrtShell
->Insert2("HHH");
3538 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3539 // Without the accompanying fix in place, this test would have failed with:
3542 // i.e. the italic string was broken into 2 lines, while Word kept it in a single line.
3543 assertXPath(pXmlDoc
, "/root/page/body/txt[1]/LineBreak", 1);
3546 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testContinuousEndnotesInsertPageAtStart
)
3548 // Create a new document with CONTINUOUS_ENDNOTES enabled.
3549 SwDoc
* pDoc
= createSwDoc();
3550 pDoc
->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES
, true);
3552 // Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on
3554 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
3555 pWrtShell
->InsertPageBreak();
3556 pWrtShell
->InsertFootnote("endnote", /*bEndNote=*/true, /*bEdit=*/false);
3558 // Add a new page at the start of the document.
3559 pWrtShell
->SttEndDoc(/*bStart=*/true);
3560 pWrtShell
->InsertPageBreak();
3562 // Make sure that the endnote is moved from the 2nd page to the 3rd one.
3563 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3564 assertXPath(pXmlDoc
, "/root/page", 3);
3565 // Without the accompanying fix in place, this test would have failed with:
3568 // i.e. the footnote container remained on page 2.
3569 assertXPath(pXmlDoc
, "/root/page[3]/ftncont", 1);
3572 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testContinuousEndnotesDeletePageAtStart
)
3574 // Create a new document with CONTINUOUS_ENDNOTES enabled.
3575 SwDoc
* pDoc
= createSwDoc();
3576 pDoc
->getIDocumentSettingAccess().set(DocumentSettingId::CONTINUOUS_ENDNOTES
, true);
3578 // Insert a second page, and an endnote on the 2nd page (both the anchor and the endnote is on
3580 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
3581 pWrtShell
->InsertPageBreak();
3582 pWrtShell
->InsertFootnote("endnote", /*bEndNote=*/true, /*bEdit=*/false);
3584 // Remove the empty page at the start of the document.
3585 pWrtShell
->SttEndDoc(/*bStart=*/true);
3586 pWrtShell
->DelRight();
3588 // Make sure that the endnote is moved from the 2nd page to the 1st one.
3589 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3590 // Without the accompanying fix in place, this test would have failed with:
3593 // i.e. the endnote remained on an (otherwise) empty 2nd page.
3594 assertXPath(pXmlDoc
, "/root/page", 1);
3595 assertXPath(pXmlDoc
, "/root/page[1]/ftncont", 1);
3598 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf128399
)
3600 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf128399.docx");
3601 SwRootFrame
* pLayout
= pDoc
->getIDocumentLayoutAccess().GetCurrentLayout();
3602 SwFrame
* pPage
= pLayout
->GetLower();
3603 SwFrame
* pBody
= pPage
->GetLower();
3604 SwFrame
* pTable
= pBody
->GetLower();
3605 SwFrame
* pRow1
= pTable
->GetLower();
3606 SwFrame
* pRow2
= pRow1
->GetNext();
3607 const SwRect
& rRow2Rect
= pRow2
->getFrameArea();
3608 Point aPoint
= rRow2Rect
.Center();
3610 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
3611 SwPosition aPosition
= *pWrtShell
->GetCursor()->Start();
3612 SwPosition
aFirstRow(aPosition
);
3613 SwCursorMoveState
aState(CursorMoveState::NONE
);
3614 pLayout
->GetModelPositionForViewPoint(&aPosition
, aPoint
, &aState
);
3615 // Second row is +3: end node, start node and the first text node in the 2nd row.
3616 SwNodeOffset nExpected
= aFirstRow
.nNode
.GetIndex() + 3;
3618 // Without the accompanying fix in place, this test would have failed with:
3621 // i.e. clicking on the center of the 2nd row placed the cursor in the 1st row.
3622 CPPUNIT_ASSERT_EQUAL(nExpected
, aPosition
.nNode
.GetIndex());
3625 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf105481
)
3627 createSwDoc(DATA_DIRECTORY
, "tdf105481.odt");
3628 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3629 CPPUNIT_ASSERT(pXmlDoc
);
3631 // Without the accompanying fix in place, this test would have failed
3632 // because the vertical position of the as-char shape object and the
3633 // as-char math object will be wrong (below/beyond the text frame's bottom).
3635 SwTwips nTxtTop
= getXPath(pXmlDoc
,
3636 "/root/page/anchored/fly/txt[2]"
3640 SwTwips nTxtBottom
= nTxtTop
3642 "/root/page/anchored/fly/txt[2]"
3647 SwTwips nFormula1Top
= getXPath(pXmlDoc
,
3648 "/root/page/anchored/fly/txt[2]"
3649 "/anchored/fly[1]/infos/bounds",
3652 SwTwips nFormula1Bottom
= nFormula1Top
3654 "/root/page/anchored/fly/txt[2]"
3655 "/anchored/fly[1]/infos/bounds",
3659 SwTwips nFormula2Top
= getXPath(pXmlDoc
,
3660 "/root/page/anchored/fly/txt[2]"
3661 "/anchored/fly[2]/infos/bounds",
3664 SwTwips nFormula2Bottom
= nFormula2Top
3666 "/root/page/anchored/fly/txt[2]"
3667 "/anchored/fly[2]/infos/bounds",
3671 // Ensure that the two formula positions are at least between top and bottom of the text frame.
3672 // The below two are satisfied even without the fix.
3673 CPPUNIT_ASSERT_GREATEREQUAL(nTxtTop
, nFormula1Top
);
3674 CPPUNIT_ASSERT_GREATEREQUAL(nTxtTop
, nFormula2Top
);
3676 // Without the accompanying fix in place, this test would have failed with:
3677 // - Expected less than or equal to : 14423
3679 // that is, the formula is below the text-frame's y bound.
3680 CPPUNIT_ASSERT_LESSEQUAL(nTxtBottom
, nFormula1Bottom
);
3681 // Similarly for formula # 2 :
3682 // - Expected less than or equal to : 14423
3684 // that is, the formula is below the text-frame's y bound.
3685 CPPUNIT_ASSERT_LESSEQUAL(nTxtBottom
, nFormula2Bottom
);
3688 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf117982
)
3690 SwDoc
* pDocument
= createSwDoc(DATA_DIRECTORY
, "tdf117982.docx");
3691 SwDocShell
* pShell
= pDocument
->GetDocShell();
3692 std::shared_ptr
<GDIMetaFile
> xMetaFile
= pShell
->GetPreviewMetaFile();
3693 MetafileXmlDump dumper
;
3694 xmlDocUniquePtr pXmlDoc
= dumpAndParse(dumper
, *xMetaFile
);
3695 assertXPathContent(pXmlDoc
, "/metafile/push[1]/push[1]/push[1]/textarray[1]/text", "FOO AAA");
3696 //The first cell must be "FOO AAA". If not, this means the first cell content not visible in
3697 //the source document.
3700 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf128959
)
3702 // no orphan/widow control in table cells
3703 SwDoc
* pDocument
= createSwDoc(DATA_DIRECTORY
, "tdf128959.docx");
3704 CPPUNIT_ASSERT(pDocument
);
3705 discardDumpedLayout();
3706 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3708 // first two lines of the paragraph in the split table cell on the first page
3709 // (these lines were completely lost)
3711 pXmlDoc
, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/LineBreak[1]", "Line",
3712 "a)Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas porttitor congue ");
3714 pXmlDoc
, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt[1]/LineBreak[2]", "Line",
3715 "massa. Fusce posuere, magna sed pulvinar ultricies, purus lectus malesuada libero, sit ");
3716 // last line of the paragraph in the split table cell on the second page
3717 assertXPath(pXmlDoc
, "/root/page[2]/body/tab[1]/row[1]/cell[1]/txt[1]/LineBreak[1]", "Line",
3718 "amet commodo magna eros quis urna.");
3721 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf121658
)
3723 uno::Reference
<linguistic2::XHyphenator
> xHyphenator
= LinguMgr::GetHyphenator();
3724 if (!xHyphenator
->hasLocale(lang::Locale("en", "US", OUString())))
3727 createSwDoc(DATA_DIRECTORY
, "tdf121658.odt");
3728 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3730 // Only 2 hyphenated words should appear in the document (in the lowercase words).
3731 // Uppercase words should not be hyphenated.
3732 assertXPath(pXmlDoc
, "//Special[@nType='PortionType::Hyphen']", 2);
3735 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testWriterImageNoCapture
)
3737 createSwDoc(DATA_DIRECTORY
, "writer-image-no-capture.docx");
3738 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3739 CPPUNIT_ASSERT(pXmlDoc
);
3740 sal_Int32 nPageLeft
= getXPath(pXmlDoc
, "//page/infos/bounds", "left").toInt32();
3741 sal_Int32 nImageLeft
= getXPath(pXmlDoc
, "//anchored/fly/infos/bounds", "left").toInt32();
3742 // Without the accompanying fix in place, this test would have failed with:
3743 // - Expected less than: 284
3745 // i.e. the image position was modified to be inside the page frame ("captured"), even if Word
3746 // does not do that.
3747 CPPUNIT_ASSERT_LESS(nPageLeft
, nImageLeft
);
3750 static SwRect
lcl_getVisibleFlyObjRect(SwWrtShell
* pWrtShell
)
3752 SwRootFrame
* pRoot
= pWrtShell
->GetLayout();
3753 SwPageFrame
* pPage
= static_cast<SwPageFrame
*>(pRoot
->GetLower());
3754 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
3755 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
3756 SwSortedObjs
* pDrawObjs
= pPage
->GetDrawObjs();
3757 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDrawObjs
->size());
3758 SwAnchoredObject
* pDrawObj
= (*pDrawObjs
)[0];
3759 CPPUNIT_ASSERT_EQUAL(OUString("Rahmen8"), pDrawObj
->GetFrameFormat().GetName());
3760 pPage
= static_cast<SwPageFrame
*>(pPage
->GetNext());
3761 pDrawObjs
= pPage
->GetDrawObjs();
3762 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDrawObjs
->size());
3763 pDrawObj
= (*pDrawObjs
)[0];
3764 CPPUNIT_ASSERT_EQUAL(OUString("Rahmen123"), pDrawObj
->GetFrameFormat().GetName());
3765 SwRect aFlyRect
= pDrawObj
->GetObjRect();
3766 CPPUNIT_ASSERT(pPage
->getFrameArea().Contains(aFlyRect
));
3770 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testStableAtPageAnchoredFlyPosition
)
3772 // this doc has two page-anchored frames: one tiny on page 3 and one large on page 4.
3773 // it also has a style:master-page named "StandardEntwurf", which contains some fields.
3774 // if you add a break to page 2, or append some text to page 4 (or just toggle display field names),
3775 // the page anchored frame on page 4 vanishes, as it is incorrectly moved out of the page bounds.
3776 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "stable-at-page-anchored-fly-position.odt");
3777 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
3779 // look up the layout position of the page-bound frame on page four
3780 SwRect aOrigRect
= lcl_getVisibleFlyObjRect(pWrtShell
);
3782 // append some text to the document to trigger bug / relayout
3783 pWrtShell
->SttEndDoc(false);
3784 pWrtShell
->Insert("foo");
3786 // get the current position of the frame on page four
3787 SwRect aRelayoutRect
= lcl_getVisibleFlyObjRect(pWrtShell
);
3789 // the anchored frame should not have moved
3790 CPPUNIT_ASSERT_EQUAL(aOrigRect
, aRelayoutRect
);
3793 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf134548
)
3795 createSwDoc(DATA_DIRECTORY
, "tdf134548.odt");
3796 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3798 // Second paragraph has two non zero width tabs in beginning of line
3800 OUString sNodeType
= parseDump("/root/page/body/txt[2]/Text[1]", "nType");
3801 CPPUNIT_ASSERT_EQUAL(OUString("PortionType::TabLeft"), sNodeType
);
3802 sal_Int32 nWidth
= parseDump("/root/page/body/txt[2]/Text[1]", "nWidth").toInt32();
3803 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth
);
3806 OUString sNodeType
= parseDump("/root/page/body/txt[2]/Text[2]", "nType");
3807 CPPUNIT_ASSERT_EQUAL(OUString("PortionType::TabLeft"), sNodeType
);
3808 sal_Int32 nWidth
= parseDump("/root/page/body/txt[2]/Text[2]", "nWidth").toInt32();
3809 CPPUNIT_ASSERT_GREATER(sal_Int32(0), nWidth
);
3813 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf124423
)
3815 createSwDoc(DATA_DIRECTORY
, "tdf124423.docx");
3816 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3817 sal_Int32 nFly1Width
3818 = getXPath(pXmlDoc
, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
3819 sal_Int32 nFly2Width
3820 = getXPath(pXmlDoc
, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
3821 sal_Int32 nPageWidth
= getXPath(pXmlDoc
, "//page/infos/prtBounds", "width").toInt32();
3822 CPPUNIT_ASSERT_EQUAL(nPageWidth
, nFly2Width
);
3823 CPPUNIT_ASSERT_LESS(nPageWidth
/ 2, nFly1Width
);
3825 createSwDoc(DATA_DIRECTORY
, "tdf124423.odt");
3826 pXmlDoc
= parseLayoutDump();
3827 nFly1Width
= getXPath(pXmlDoc
, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
3828 nFly2Width
= getXPath(pXmlDoc
, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
3829 nPageWidth
= getXPath(pXmlDoc
, "//page/infos/prtBounds", "width").toInt32();
3830 CPPUNIT_ASSERT_LESS(nPageWidth
/ 2, nFly2Width
);
3831 CPPUNIT_ASSERT_LESS(nPageWidth
/ 2, nFly1Width
);
3834 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf137185
)
3836 // First load the sample bugdoc
3837 load(DATA_DIRECTORY
, "tdf137185.odt");
3838 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
3839 CPPUNIT_ASSERT(pTextDoc
);
3840 // Get the doc shell
3841 SwDoc
* pDoc(pTextDoc
->GetDocShell()->GetDoc());
3843 // Get the DrawObject from page
3844 auto pModel
= pDoc
->getIDocumentDrawModelAccess().GetDrawModel();
3845 CPPUNIT_ASSERT(pModel
);
3846 auto pPage
= pModel
->GetPage(0);
3847 CPPUNIT_ASSERT(pPage
);
3848 auto pObj
= pPage
->GetObj(0);
3849 CPPUNIT_ASSERT(pObj
);
3851 // Get the format of the draw object
3852 auto pShape
= FindFrameFormat(pObj
);
3853 CPPUNIT_ASSERT(pShape
);
3855 // Check the text of the shape
3856 uno::Reference
<text::XText
> xTxt(getShape(1), uno::UNO_QUERY
);
3857 CPPUNIT_ASSERT_EQUAL(OUString("Align me!"), xTxt
->getText()->getString());
3859 // Add a textbox to the shape
3860 SwTextBoxHelper::create(pShape
, pShape
->FindRealSdrObject(), true);
3862 // Check if the text moved from the shape to the frame
3863 auto pFormat
= SwTextBoxHelper::getOtherTextBoxFormat(getShape(1));
3864 auto xTextFrame
= SwXTextFrame::CreateXTextFrame(*pFormat
->GetDoc(), pFormat
);
3866 CPPUNIT_ASSERT_EQUAL(OUString("Align me!"), xTextFrame
->getText()->getString());
3867 SdrTextObj
* pTextObj
= dynamic_cast<SdrTextObj
*>(pObj
);
3868 CPPUNIT_ASSERT(pTextObj
);
3869 const auto& aOutStr
= pTextObj
->GetOutlinerParaObject()->GetTextObject();
3871 CPPUNIT_ASSERT(aOutStr
.GetText(0).isEmpty());
3872 // Before the patch it failed, because the text appeared 2 times on each other.
3875 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf138782
)
3877 CPPUNIT_ASSERT(createSwDoc(DATA_DIRECTORY
, "tdf138782.docx"));
3878 auto pXml
= parseLayoutDump();
3879 CPPUNIT_ASSERT(pXml
);
3881 // Without the fix it failed because the 3rd shape was outside the page:
3882 // - Expected less than: 13327
3885 CPPUNIT_ASSERT_LESS(
3886 getXPath(pXml
, "/root/page/infos/bounds", "right").toInt32(),
3887 getXPath(pXml
, "/root/page/body/txt[8]/anchored/SwAnchoredDrawObject/bounds", "right")
3891 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf135035
)
3893 createSwDoc(DATA_DIRECTORY
, "tdf135035.docx");
3894 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3895 sal_Int32 nFly1Width
3896 = getXPath(pXmlDoc
, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
3897 sal_Int32 nFly2Width
3898 = getXPath(pXmlDoc
, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
3899 sal_Int32 nFly3Width
3900 = getXPath(pXmlDoc
, "(//anchored/fly)[3]/infos/prtBounds", "width").toInt32();
3901 sal_Int32 nParentWidth
= getXPath(pXmlDoc
, "(//txt)[1]/infos/prtBounds", "width").toInt32();
3902 CPPUNIT_ASSERT_EQUAL(nParentWidth
, nFly2Width
);
3903 CPPUNIT_ASSERT_EQUAL(nParentWidth
, nFly3Width
);
3904 CPPUNIT_ASSERT_LESS(nParentWidth
/ 2, nFly1Width
);
3906 createSwDoc(DATA_DIRECTORY
, "tdf135035.odt");
3907 pXmlDoc
= parseLayoutDump();
3908 nFly1Width
= getXPath(pXmlDoc
, "(//anchored/fly)[1]/infos/prtBounds", "width").toInt32();
3909 nFly2Width
= getXPath(pXmlDoc
, "(//anchored/fly)[2]/infos/prtBounds", "width").toInt32();
3910 nFly3Width
= getXPath(pXmlDoc
, "(//anchored/fly)[3]/infos/prtBounds", "width").toInt32();
3911 nParentWidth
= getXPath(pXmlDoc
, "(//txt)[1]/infos/prtBounds", "width").toInt32();
3912 CPPUNIT_ASSERT_LESS(nParentWidth
/ 2, nFly2Width
);
3913 CPPUNIT_ASSERT_LESS(nParentWidth
/ 2, nFly1Width
);
3914 CPPUNIT_ASSERT_GREATER(nParentWidth
, nFly3Width
);
3917 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf146704_EndnoteInSection
)
3919 SwDoc
* pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf146704_EndnoteInSection.odt");
3920 CPPUNIT_ASSERT(pDoc
);
3921 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3922 // Without the fix, the endnote placed to 2. page
3923 assertXPath(pXmlDoc
, "/root/page", 1);
3926 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf139336_ColumnsWithFootnoteDoNotOccupyEntirePage
)
3929 = createSwDoc(DATA_DIRECTORY
, "tdf139336_ColumnsWithFootnoteDoNotOccupyEntirePage.docx");
3930 CPPUNIT_ASSERT(pDoc
);
3931 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3932 // Without the fix, it would be 5 pages, but with the fix the whole document
3933 // would fit into 1 page, but it will be 2 pages right now, because
3934 // when writer import (from docx) the last section with columns, then it does not set
3935 // the evenly distributed settings, and this settings is required for the fix now, to
3936 // avoid some regression.
3937 assertXPath(pXmlDoc
, "/root/page", 2);
3940 CPPUNIT_TEST_FIXTURE(SwLayoutWriter
, testTdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage
)
3942 // Old odt files should keep their original layout, as it was before Tdf139336 fix.
3943 // The new odt file is only 1 page long, while the old odt file (with the same content)
3944 // was more then 1 page long.
3945 // Note: Somewhy this test miscalculates the layout of the old odt file.
3946 // It will be 4 pages long, while opened in Writer it is 5 pages long.
3948 = createSwDoc(DATA_DIRECTORY
, "tdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage_Old.odt");
3949 CPPUNIT_ASSERT(pDoc
);
3950 Scheduler::ProcessEventsToIdle();
3951 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
3952 xmlXPathObjectPtr pXmlObj
= getXPathNode(pXmlDoc
, "/root/page");
3953 xmlNodeSetPtr pXmlNodes
= pXmlObj
->nodesetval
;
3954 CPPUNIT_ASSERT_GREATER(1, xmlXPathNodeSetGetLength(pXmlNodes
));
3955 xmlXPathFreeObject(pXmlObj
);
3957 discardDumpedLayout();
3958 pDoc
= createSwDoc(DATA_DIRECTORY
, "tdf54465_ColumnsWithFootnoteDoNotOccupyEntirePage_New.odt");
3959 CPPUNIT_ASSERT(pDoc
);
3960 pXmlDoc
= parseLayoutDump();
3961 assertXPath(pXmlDoc
, "/root/page", 1);
3964 CPPUNIT_PLUGIN_IMPLEMENT();
3966 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */