tdf#62032 use style list level when changing style
[LibreOffice.git] / sw / qa / extras / uiwriter / uiwriter4.cxx
blob803c4821e4a53e812716f4ddd752e1f5a3d38a23
2 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4 * This file is part of the LibreOffice project.
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
11 #include <memory>
12 #include <string_view>
14 #include <com/sun/star/awt/FontWeight.hpp>
15 #include <com/sun/star/drawing/GraphicExportFilter.hpp>
16 #include <com/sun/star/drawing/FillStyle.hpp>
17 #include <com/sun/star/i18n/TextConversionOption.hpp>
18 #include <com/sun/star/style/CaseMap.hpp>
19 #include <vcl/errcode.hxx>
20 #include <tools/gen.hxx>
21 #include <swmodeltestbase.hxx>
22 #include <ndtxt.hxx>
23 #include <wrtsh.hxx>
24 #include <shellio.hxx>
25 #include <expfld.hxx>
26 #include <drawdoc.hxx>
27 #include <docary.hxx>
28 #include <redline.hxx>
29 #include <section.hxx>
30 #include <fmtclds.hxx>
31 #include <dcontact.hxx>
32 #include <textboxhelper.hxx>
33 #include <view.hxx>
34 #include <hhcwrp.hxx>
35 #include <swacorr.hxx>
36 #include <swmodule.hxx>
37 #include <modcfg.hxx>
38 #include <charatr.hxx>
39 #include <editeng/acorrcfg.hxx>
40 #include <unotools/streamwrap.hxx>
41 #include <unocrsr.hxx>
42 #include <unocrsrhelper.hxx>
43 #include <unotbl.hxx>
44 #include <IMark.hxx>
45 #include <IDocumentMarkAccess.hxx>
46 #include <IDocumentSettingAccess.hxx>
47 #include <pagedesc.hxx>
48 #include <PostItMgr.hxx>
49 #include <AnnotationWin.hxx>
50 #include <com/sun/star/text/XDefaultNumberingProvider.hpp>
51 #include <com/sun/star/awt/FontUnderline.hpp>
52 #include <com/sun/star/text/XTextColumns.hpp>
53 #include <vcl/TypeSerializer.hxx>
55 #include <svx/svdpage.hxx>
56 #include <svx/svdview.hxx>
57 #include <svl/itemiter.hxx>
58 #include <svx/svxids.hrc>
59 #include <unotools/localfilehelper.hxx>
60 #include <vcl/filter/PDFiumLibrary.hxx>
62 #include <editeng/eeitem.hxx>
63 #include <editeng/scripttypeitem.hxx>
64 #include <editeng/fontitem.hxx>
65 #include <editeng/lrspitem.hxx>
66 #include <editeng/opaqitem.hxx>
67 #include <editeng/protitem.hxx>
68 #include <editeng/ulspitem.hxx>
69 #include <editeng/wghtitem.hxx>
70 #include <i18nutil/transliteration.hxx>
71 #include <i18nutil/searchopt.hxx>
72 #include <reffld.hxx>
73 #include <dbfld.hxx>
74 #include <txatbase.hxx>
75 #include <txtftn.hxx>
76 #include <IDocumentDrawModelAccess.hxx>
77 #include <IDocumentFieldsAccess.hxx>
78 #include <IDocumentRedlineAccess.hxx>
79 #include <IDocumentState.hxx>
80 #include <unofldmid.h>
81 #include <UndoManager.hxx>
82 #include <textsh.hxx>
83 #include <frmatr.hxx>
84 #include <frmmgr.hxx>
85 #include <tblafmt.hxx>
87 #include <com/sun/star/lang/Locale.hpp>
88 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
89 #include <com/sun/star/util/XNumberFormatTypes.hpp>
90 #include <com/sun/star/util/NumberFormat.hpp>
91 #include <com/sun/star/util/XNumberFormatsSupplier.hpp>
92 #include <com/sun/star/util/SearchAlgorithms2.hpp>
93 #include <com/sun/star/util/SearchFlags.hpp>
94 #include <com/sun/star/util/SearchAlgorithms.hpp>
95 #include <com/sun/star/sdb/DatabaseContext.hpp>
96 #include <com/sun/star/sdbcx/XTablesSupplier.hpp>
97 #include <com/sun/star/sdbc/XDataSource.hpp>
98 #include <com/sun/star/text/XParagraphCursor.hpp>
99 #include <com/sun/star/util/XPropertyReplace.hpp>
100 #include <com/sun/star/beans/PropertyAttribute.hpp>
101 #include <com/sun/star/text/XTextField.hpp>
102 #include <com/sun/star/text/TextMarkupType.hpp>
103 #include <com/sun/star/chart2/data/XDataSource.hpp>
104 #include <com/sun/star/document/XEmbeddedObjectSupplier2.hpp>
105 #include <com/sun/star/drawing/XShape.hpp>
106 #include <com/sun/star/text/XTextTable.hpp>
107 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
108 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
109 #include <com/sun/star/text/XPageCursor.hpp>
110 #include <o3tl/cppunittraitshelper.hxx>
111 #include <o3tl/unit_conversion.hxx>
112 #include <osl/file.hxx>
113 #include <osl/thread.hxx>
114 #include <paratr.hxx>
115 #include <drawfont.hxx>
116 #include <txtfrm.hxx>
117 #include <txttypes.hxx>
118 #include <SwPortionHandler.hxx>
119 #include <hyp.hxx>
120 #include <swdtflvr.hxx>
121 #include <editeng/svxenum.hxx>
122 #include <comphelper/propertysequence.hxx>
123 #include <sfx2/classificationhelper.hxx>
124 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
125 #include <sfx2/docfilt.hxx>
126 #include <sfx2/viewfrm.hxx>
127 #include <sfx2/dispatch.hxx>
128 #include <comphelper/configurationhelper.hxx>
129 #include <editeng/unolingu.hxx>
130 #include <vcl/scheduler.hxx>
131 #include <config_features.h>
132 #include <sfx2/watermarkitem.hxx>
133 #include <sfx2/fcontnr.hxx>
134 #include <sfx2/docfile.hxx>
135 #include <test/htmltesttools.hxx>
136 #include <fmthdft.hxx>
137 #include <iodetect.hxx>
138 #include <wrthtml.hxx>
139 #include <dbmgr.hxx>
140 #include <frameformats.hxx>
141 #include <docsh.hxx>
142 #include <unotxdoc.hxx>
143 #include <comphelper/processfactory.hxx>
144 #include <rootfrm.hxx>
146 namespace
148 constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/extras/uiwriter/data/";
150 sal_Int32 lcl_getAttributeIDFromHints(const SwpHints& hints)
152 for (size_t i = 0; i < hints.Count(); ++i)
154 const SwTextAttr* hint = hints.Get(i);
155 if (hint->Which() == RES_TXTATR_AUTOFMT)
157 const SwFormatAutoFormat& rFmt = hint->GetAutoFormat();
158 SfxItemIter aIter(*rFmt.GetStyleHandle());
159 return aIter.GetCurItem()->Which();
162 return -1;
166 class SwUiWriterTest4 : public SwModelTestBase, public HtmlTestTools
168 public:
169 void testTdf96515();
170 void testTdf96943();
171 void testTdf96536();
172 void testTdf96479();
173 void testBookmarkCollapsed();
174 void testRemoveBookmarkText();
175 void testRemoveBookmarkTextAndAddNew();
176 void testRemoveBookmarkTextAndAddNewAfterReload();
177 void testTdf96961();
178 void testTdf88453();
179 void testTdf88453Table();
180 void testClassificationPaste();
181 void testSmallCaps();
182 void testTdf98987();
183 void testTdf99004();
184 void testTdf84695();
185 void testTdf84695NormalChar();
186 void testTdf84695Tab();
187 void testTableStyleUndo();
188 void testRedlineCopyPaste();
189 void testTdf135260();
190 void testRedlineParam();
191 void testRedlineViewAuthor();
192 void testTdf91292();
193 void testTdf78727();
194 void testRedlineTimestamp();
195 void testCursorWindows();
196 void testLandscape();
197 void testTdf95699();
198 void testTdf104032();
199 void testTdf104440();
200 void testTdf104425();
201 void testTdf104814();
202 void testTableRedlineRedoCrash();
203 void testTableRemoveHasTextChangesOnly();
204 void testTableRemoveHasTextChangesOnly2();
205 void testTdf147182_AcceptAllChangesInTableSelection();
206 void testTdf66405();
207 void testTdf35021_tabOverMarginDemo();
208 void testTdf106701_tabOverMarginAutotab();
209 void testTdf104492();
210 void testTdf107025();
211 void testTdf107362();
212 void testTdf105417();
213 void testTdf105625();
214 void testTdf125151_protected();
215 void testTdf125151_protectedB();
216 void testTdf106736();
217 void testTdf58604();
218 void testTdf112025();
219 void testTdf72942();
221 void testTdf113877_mergeDocs(const char* aDestDoc, const char* aInsertDoc);
222 void testTdf113877();
223 void testTdf113877NoMerge();
224 void testTdf113877_default_style();
225 void testTdf113877_Standard_style();
226 void testTdf113877_blank_bold_on();
227 void testTdf113877_blank_bold_off();
229 void testMsWordCompTrailingBlanks();
230 void testCreateDocxAnnotation();
231 void testTdf107976();
232 void testTdf142157();
233 void testTdf116640();
234 void testTdf108524();
235 void testRhbz1810732();
236 void testTableInSection();
237 void testTableInNestedSection();
238 void testTableInSectionInTable();
239 void testSectionInTableInTable();
240 void testSectionInTableInTable2();
241 void testSectionInTableInTable3();
242 void testSectionInTableInTable4();
243 void testTdf112160();
244 void testLinesMoveBackwardsInSectionInTable();
245 void testTdf112741();
246 void testTdf112860();
247 void testTdf113287();
248 void testTdf113445();
249 void testTdf113686();
250 void testFontEmbedding();
251 void testLinesInSectionInTable();
252 void testParagraphOfTextRange();
253 void testTdf99689TableOfContents();
254 void testTdf99689TableOfFigures();
255 void testTdf99689TableOfTables();
256 void testTdf112448();
257 void testTdf113790();
258 void testTdf108048();
259 void testTdf114306();
260 void testTdf114306_2();
261 void testTdf113481();
262 void testTdf115013();
263 void testTdf114536();
264 void testTdf115065();
265 void testTdf84806_MovingMultipleTableRows();
266 void testTdf147181_TrackedMovingOfMultipleTableRows();
267 void testTdf115132();
268 void testXDrawPagesSupplier();
269 void testTdf116403();
270 void testHtmlCopyImages();
271 void testTdf116789();
272 void testTdf91801();
273 void testTdf51223();
274 void testTdf108423();
275 void testTdf106164();
276 void testTdf54409();
277 void testTdf38394();
278 void testTdf59666();
279 void testTdf133524();
280 void testTdf133524_Romanian();
281 void testTdf128860();
282 void testTdf123786();
283 void testTdf133589();
284 void testTdf143176();
285 void testInconsistentBookmark();
286 void testInsertLongDateFormat();
287 void testSpellOnlineParameter();
288 void testRedlineAutoCorrect();
289 void testRedlineAutoCorrect2();
290 void testEmojiAutoCorrect();
291 void testTdf129270();
292 void testInsertPdf();
293 void testTdf143760WrapContourToOff();
294 void testHatchFill();
295 void testTdf62032ApplyStyle();
297 CPPUNIT_TEST_SUITE(SwUiWriterTest4);
298 CPPUNIT_TEST(testTdf96515);
299 CPPUNIT_TEST(testTdf96943);
300 CPPUNIT_TEST(testTdf96536);
301 CPPUNIT_TEST(testTdf96479);
302 CPPUNIT_TEST(testBookmarkCollapsed);
303 CPPUNIT_TEST(testRemoveBookmarkText);
304 CPPUNIT_TEST(testRemoveBookmarkTextAndAddNew);
305 CPPUNIT_TEST(testRemoveBookmarkTextAndAddNewAfterReload);
306 CPPUNIT_TEST(testTdf96961);
307 CPPUNIT_TEST(testTdf88453);
308 CPPUNIT_TEST(testTdf88453Table);
309 CPPUNIT_TEST(testClassificationPaste);
310 CPPUNIT_TEST(testSmallCaps);
311 CPPUNIT_TEST(testTdf98987);
312 CPPUNIT_TEST(testTdf99004);
313 CPPUNIT_TEST(testTdf84695);
314 CPPUNIT_TEST(testTdf84695NormalChar);
315 CPPUNIT_TEST(testTdf84695Tab);
316 CPPUNIT_TEST(testTableStyleUndo);
317 CPPUNIT_TEST(testRedlineCopyPaste);
318 CPPUNIT_TEST(testTdf135260);
319 CPPUNIT_TEST(testRedlineParam);
320 CPPUNIT_TEST(testRedlineViewAuthor);
321 CPPUNIT_TEST(testTdf91292);
322 CPPUNIT_TEST(testTdf78727);
323 CPPUNIT_TEST(testRedlineTimestamp);
324 CPPUNIT_TEST(testCursorWindows);
325 CPPUNIT_TEST(testLandscape);
326 CPPUNIT_TEST(testTdf95699);
327 CPPUNIT_TEST(testTdf104032);
328 CPPUNIT_TEST(testTdf104440);
329 CPPUNIT_TEST(testTdf104425);
330 CPPUNIT_TEST(testTdf104814);
331 CPPUNIT_TEST(testTableRedlineRedoCrash);
332 CPPUNIT_TEST(testTableRemoveHasTextChangesOnly);
333 CPPUNIT_TEST(testTableRemoveHasTextChangesOnly2);
334 CPPUNIT_TEST(testTdf147182_AcceptAllChangesInTableSelection);
335 CPPUNIT_TEST(testTdf66405);
336 CPPUNIT_TEST(testTdf35021_tabOverMarginDemo);
337 CPPUNIT_TEST(testTdf106701_tabOverMarginAutotab);
338 CPPUNIT_TEST(testTdf104492);
339 CPPUNIT_TEST(testTdf107025);
340 CPPUNIT_TEST(testTdf107362);
341 CPPUNIT_TEST(testTdf105417);
342 CPPUNIT_TEST(testTdf105625);
343 CPPUNIT_TEST(testTdf125151_protected);
344 CPPUNIT_TEST(testTdf125151_protectedB);
345 CPPUNIT_TEST(testTdf106736);
346 CPPUNIT_TEST(testTdf58604);
347 CPPUNIT_TEST(testTdf112025);
348 CPPUNIT_TEST(testTdf72942);
349 CPPUNIT_TEST(testTdf113877);
350 CPPUNIT_TEST(testTdf113877NoMerge);
351 CPPUNIT_TEST(testTdf113877_default_style);
352 CPPUNIT_TEST(testTdf113877_Standard_style);
353 CPPUNIT_TEST(testTdf113877_blank_bold_on);
354 CPPUNIT_TEST(testTdf113877_blank_bold_off);
355 CPPUNIT_TEST(testMsWordCompTrailingBlanks);
356 CPPUNIT_TEST(testCreateDocxAnnotation);
357 CPPUNIT_TEST(testTdf107976);
358 CPPUNIT_TEST(testTdf142157);
359 CPPUNIT_TEST(testTdf116640);
360 CPPUNIT_TEST(testTdf108524);
361 CPPUNIT_TEST(testRhbz1810732);
362 CPPUNIT_TEST(testTableInSection);
363 CPPUNIT_TEST(testTableInNestedSection);
364 CPPUNIT_TEST(testTableInSectionInTable);
365 CPPUNIT_TEST(testSectionInTableInTable);
366 CPPUNIT_TEST(testSectionInTableInTable2);
367 CPPUNIT_TEST(testSectionInTableInTable3);
368 CPPUNIT_TEST(testSectionInTableInTable4);
369 CPPUNIT_TEST(testTdf112160);
370 CPPUNIT_TEST(testLinesMoveBackwardsInSectionInTable);
371 CPPUNIT_TEST(testTdf112741);
372 CPPUNIT_TEST(testTdf112860);
373 CPPUNIT_TEST(testTdf113287);
374 CPPUNIT_TEST(testTdf113445);
375 CPPUNIT_TEST(testTdf113686);
376 CPPUNIT_TEST(testFontEmbedding);
377 CPPUNIT_TEST(testLinesInSectionInTable);
378 CPPUNIT_TEST(testParagraphOfTextRange);
379 CPPUNIT_TEST(testTdf99689TableOfContents);
380 CPPUNIT_TEST(testTdf99689TableOfFigures);
381 CPPUNIT_TEST(testTdf99689TableOfTables);
382 CPPUNIT_TEST(testTdf112448);
383 CPPUNIT_TEST(testTdf113790);
384 CPPUNIT_TEST(testTdf108048);
385 CPPUNIT_TEST(testTdf114306);
386 CPPUNIT_TEST(testTdf114306_2);
387 CPPUNIT_TEST(testTdf113481);
388 CPPUNIT_TEST(testTdf115013);
389 CPPUNIT_TEST(testTdf114536);
390 CPPUNIT_TEST(testTdf115065);
391 CPPUNIT_TEST(testTdf84806_MovingMultipleTableRows);
392 CPPUNIT_TEST(testTdf147181_TrackedMovingOfMultipleTableRows);
393 CPPUNIT_TEST(testTdf115132);
394 CPPUNIT_TEST(testXDrawPagesSupplier);
395 CPPUNIT_TEST(testTdf116403);
396 CPPUNIT_TEST(testHtmlCopyImages);
397 CPPUNIT_TEST(testTdf116789);
398 CPPUNIT_TEST(testTdf91801);
399 CPPUNIT_TEST(testTdf51223);
400 CPPUNIT_TEST(testInconsistentBookmark);
401 CPPUNIT_TEST(testTdf108423);
402 CPPUNIT_TEST(testTdf106164);
403 CPPUNIT_TEST(testTdf54409);
404 CPPUNIT_TEST(testTdf38394);
405 CPPUNIT_TEST(testTdf59666);
406 CPPUNIT_TEST(testTdf133524);
407 CPPUNIT_TEST(testTdf133524_Romanian);
408 CPPUNIT_TEST(testTdf128860);
409 CPPUNIT_TEST(testTdf123786);
410 CPPUNIT_TEST(testTdf133589);
411 CPPUNIT_TEST(testTdf143176);
412 CPPUNIT_TEST(testInsertLongDateFormat);
413 CPPUNIT_TEST(testSpellOnlineParameter);
414 CPPUNIT_TEST(testRedlineAutoCorrect);
415 CPPUNIT_TEST(testRedlineAutoCorrect2);
416 CPPUNIT_TEST(testEmojiAutoCorrect);
417 CPPUNIT_TEST(testTdf129270);
418 CPPUNIT_TEST(testInsertPdf);
419 CPPUNIT_TEST(testTdf143760WrapContourToOff);
420 CPPUNIT_TEST(testHatchFill);
421 CPPUNIT_TEST(testTdf62032ApplyStyle);
422 CPPUNIT_TEST_SUITE_END();
425 static void lcl_selectCharacters(SwPaM& rPaM, sal_Int32 first, sal_Int32 end)
427 rPaM.GetPoint()->nContent.Assign(rPaM.GetContentNode(), first);
428 rPaM.SetMark();
429 rPaM.GetPoint()->nContent.Assign(rPaM.GetContentNode(), end);
432 void SwUiWriterTest4::testTdf96515()
434 // Enable hide whitespace mode.
435 SwDoc* pDoc = createSwDoc();
436 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
437 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
438 aViewOptions.SetHideWhitespaceMode(true);
439 pWrtShell->ApplyViewOptions(aViewOptions);
440 CPPUNIT_ASSERT(pWrtShell->GetViewOptions()->IsWhitespaceHidden());
442 // Insert a new paragraph at the end of the document.
443 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
444 uno::Reference<text::XParagraphAppend> xParagraphAppend(xTextDocument->getText(),
445 uno::UNO_QUERY);
446 xParagraphAppend->finishParagraph(uno::Sequence<beans::PropertyValue>());
447 calcLayout();
449 // This was 2, a new page was created for the new paragraph.
450 CPPUNIT_ASSERT_EQUAL(1, getPages());
453 void SwUiWriterTest4::testTdf96943()
455 // Enable hide whitespace mode.
456 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf96943.odt");
457 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
458 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
459 aViewOptions.SetHideWhitespaceMode(true);
460 pWrtShell->ApplyViewOptions(aViewOptions);
462 // Insert a new character at the end of the document.
463 pWrtShell->SttEndDoc(/*bStt=*/false);
464 pWrtShell->Insert("d");
466 // This was 2, a new page was created for the new layout line.
467 CPPUNIT_ASSERT_EQUAL(1, getPages());
470 void SwUiWriterTest4::testTdf96536()
472 // Enable hide whitespace mode.
473 SwDoc* pDoc = createSwDoc();
474 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
475 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
476 aViewOptions.SetHideWhitespaceMode(true);
477 pWrtShell->ApplyViewOptions(aViewOptions);
478 CPPUNIT_ASSERT(pWrtShell->GetViewOptions()->IsWhitespaceHidden());
480 // Insert a page break and go back to the first page.
481 pWrtShell->InsertPageBreak();
482 pWrtShell->SttEndDoc(/*bStt=*/true);
483 calcLayout();
484 sal_Int32 nSingleParaPageHeight = parseDump("/root/page[1]/infos/bounds", "height").toInt32();
485 discardDumpedLayout();
487 // Insert a 2nd paragraph at the end of the first page, so the page height grows at least twice...
488 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
489 uno::Reference<text::XParagraphAppend> xParagraphAppend(xTextDocument->getText(),
490 uno::UNO_QUERY);
491 const uno::Reference<text::XTextRange> xInsertPos = getRun(getParagraph(1), 1);
492 xParagraphAppend->finishParagraphInsert(uno::Sequence<beans::PropertyValue>(), xInsertPos);
493 calcLayout();
494 CPPUNIT_ASSERT(parseDump("/root/page[1]/infos/bounds", "height").toInt32()
495 >= 2 * nSingleParaPageHeight);
496 discardDumpedLayout();
498 // ... and then delete the 2nd paragraph, which shrinks the page to the previous size.
499 uno::Reference<lang::XComponent> xParagraph(getParagraph(2), uno::UNO_QUERY);
500 xParagraph->dispose();
501 calcLayout();
502 CPPUNIT_ASSERT_EQUAL(nSingleParaPageHeight,
503 parseDump("/root/page[1]/infos/bounds", "height").toInt32());
506 void SwUiWriterTest4::testTdf96479()
508 // We want to verify the empty input text field in the bookmark
509 static const OUString emptyInputTextField
510 = OUStringChar(CH_TXT_ATR_INPUTFIELDSTART) + OUStringChar(CH_TXT_ATR_INPUTFIELDEND);
512 SwDoc* pDoc = createSwDoc();
514 // So we can clean up all references for reload
516 // Append bookmark
517 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
518 SwPaM aPaM(aIdx);
519 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
520 sw::mark::IMark* pMark = rIDMA.makeMark(
521 aPaM, "original", IDocumentMarkAccess::MarkType::BOOKMARK, ::sw::mark::InsertMode::New);
522 CPPUNIT_ASSERT(!pMark->IsExpanded());
523 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
525 // Get helper objects
526 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
527 uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
529 // Create cursor from bookmark
530 uno::Reference<text::XTextContent> xTextContent(
531 xBookmarksSupplier->getBookmarks()->getByName("original"), uno::UNO_QUERY);
532 uno::Reference<text::XTextRange> xRange = xTextContent->getAnchor();
533 uno::Reference<text::XTextCursor> xCursor
534 = xRange->getText()->createTextCursorByRange(xRange);
535 CPPUNIT_ASSERT(xCursor->isCollapsed());
537 // Remove bookmark
538 xRange->getText()->removeTextContent(xTextContent);
539 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rIDMA.getBookmarksCount());
541 // Insert replacement bookmark
542 uno::Reference<text::XTextContent> xBookmarkNew(
543 xFactory->createInstance("com.sun.star.text.Bookmark"), uno::UNO_QUERY);
544 uno::Reference<container::XNamed> xBookmarkName(xBookmarkNew, uno::UNO_QUERY);
545 xBookmarkName->setName("replacement");
546 CPPUNIT_ASSERT(xCursor->isCollapsed());
547 // Force bookmark expansion
548 xCursor->getText()->insertString(xCursor, ".", true);
549 xCursor->getText()->insertTextContent(xCursor, xBookmarkNew, true);
550 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
551 auto mark = *(rIDMA.getBookmarksBegin());
552 CPPUNIT_ASSERT(mark->IsExpanded());
554 // Create and insert input textfield with some content
555 uno::Reference<text::XTextField> xTextField(
556 xFactory->createInstance("com.sun.star.text.TextField.Input"), uno::UNO_QUERY);
557 uno::Reference<text::XTextCursor> xCursorNew(
558 xBookmarkNew->getAnchor()->getText()->createTextCursorByRange(
559 xBookmarkNew->getAnchor()));
560 CPPUNIT_ASSERT(!xCursorNew->isCollapsed());
561 xCursorNew->getText()->insertTextContent(xCursorNew, xTextField, true);
562 xBookmarkNew = uno::Reference<text::XTextContent>(
563 xBookmarksSupplier->getBookmarks()->getByName("replacement"), uno::UNO_QUERY);
564 xCursorNew = xBookmarkNew->getAnchor()->getText()->createTextCursorByRange(
565 xBookmarkNew->getAnchor());
566 CPPUNIT_ASSERT(!xCursorNew->isCollapsed());
568 // Can't check the actual content of the text node via UNO
569 mark = *(rIDMA.getBookmarksBegin());
570 CPPUNIT_ASSERT(mark->IsExpanded());
571 SwPaM pam(mark->GetMarkStart(), mark->GetMarkEnd());
572 // Check for the actual bug, which didn't include CH_TXT_ATR_INPUTFIELDEND in the bookmark
573 CPPUNIT_ASSERT_EQUAL(emptyInputTextField, pam.GetText());
577 // Save and load cycle
578 // Actually not needed, but the bug symptom of a missing bookmark
579 // occurred because a broken bookmark was saved and loading silently
580 // dropped the broken bookmark!
581 reload("writer8", "testTdf96479.odt");
582 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
583 CPPUNIT_ASSERT(pTextDoc);
584 pDoc = pTextDoc->GetDocShell()->GetDoc();
586 // Lookup "replacement" bookmark
587 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
588 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
589 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
590 CPPUNIT_ASSERT(xBookmarksSupplier->getBookmarks()->hasByName("replacement"));
592 uno::Reference<text::XTextContent> xTextContent(
593 xBookmarksSupplier->getBookmarks()->getByName("replacement"), uno::UNO_QUERY);
594 uno::Reference<text::XTextRange> xRange = xTextContent->getAnchor();
595 uno::Reference<text::XTextCursor> xCursor
596 = xRange->getText()->createTextCursorByRange(xRange);
597 CPPUNIT_ASSERT(!xCursor->isCollapsed());
599 // Verify bookmark content via text node / PaM
600 auto mark = *(rIDMA.getBookmarksBegin());
601 CPPUNIT_ASSERT(mark->IsExpanded());
602 SwPaM pam(mark->GetMarkStart(), mark->GetMarkEnd());
603 CPPUNIT_ASSERT_EQUAL(emptyInputTextField, pam.GetText());
607 // If you resave original document the bookmark will be changed from
609 // <text:p text:style-name="Standard">
610 // <text:bookmark-start text:name="test"/>
611 // <text:bookmark-end text:name="test"/>
612 // def
613 // </text:p>
615 // to
617 // <text:p text:style-name="Standard">
618 // <text:bookmark text:name="test"/>
619 // def
620 // </text:p>
622 void SwUiWriterTest4::testBookmarkCollapsed()
624 // load document
625 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "collapsed_bookmark.odt");
626 CPPUNIT_ASSERT(pDoc);
628 // save original document
629 utl::TempFile aTempFile;
630 save("writer8", aTempFile);
632 // load only content.xml from the resaved document
633 if (xmlDocUniquePtr pXmlDoc = parseExportInternal(aTempFile.GetURL(), "content.xml"))
635 const OString aPath("/office:document-content/office:body/office:text/text:p");
637 const int pos1 = getXPathPosition(pXmlDoc, aPath, "bookmark");
638 CPPUNIT_ASSERT_EQUAL(0, pos1); // found, and it is first
640 CPPUNIT_ASSERT_ASSERTION_FAIL(
641 getXPathPosition(pXmlDoc, aPath, "bookmark-start")); // not found
642 CPPUNIT_ASSERT_ASSERTION_FAIL(
643 getXPathPosition(pXmlDoc, aPath, "bookmark-end")); // not found
647 // 1. Open a new writer document
648 // 2. Enter the text "abcdef"
649 // 3. Select "abc"
650 // 4. Insert a bookmark on "abc" using Insert->Bookmark. Name the bookmark "test".
651 // 5. Open the navigator (F5)
652 // Select the bookmark "test" using the navigator.
653 // 6. Hit Del, thus deleting "abc" (The bookmark "test" is still there).
654 // 7. Save the document:
655 // <text:p text:style-name="Standard">
656 // <text:bookmark-start text:name="test"/>
657 // <text:bookmark-end text:name="test"/>
658 // def
659 // </text:p>
661 void SwUiWriterTest4::testRemoveBookmarkText()
663 // create document
665 // create a text document with "abcdef"
666 SwDoc* pDoc = createSwDoc();
669 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
670 SwPaM aPaM(aIdx);
671 pDoc->getIDocumentContentOperations().InsertString(aPaM, "abcdef");
674 // mark "abc" with "testBookmark" bookmark
676 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
677 SwPaM aPaM(aIdx);
679 lcl_selectCharacters(aPaM, 0, 3);
680 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
681 sw::mark::IMark* pMark
682 = rIDMA.makeMark(aPaM, "testBookmark", IDocumentMarkAccess::MarkType::BOOKMARK,
683 ::sw::mark::InsertMode::New);
685 // verify
686 CPPUNIT_ASSERT(pMark->IsExpanded());
687 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
690 // remove text marked with bookmark
692 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
693 SwPaM aPaM(aIdx);
695 lcl_selectCharacters(aPaM, 0, 3);
696 pDoc->getIDocumentContentOperations().DeleteRange(aPaM);
698 // verify: bookmark is still exist
699 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
700 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
704 // save document
705 utl::TempFile aTempFile;
706 save("writer8", aTempFile);
708 // load only content.xml from the resaved document
709 if (xmlDocUniquePtr pXmlDoc = parseExportInternal(aTempFile.GetURL(), "content.xml"))
711 const OString aPath("/office:document-content/office:body/office:text/text:p");
713 CPPUNIT_ASSERT_ASSERTION_FAIL(getXPathPosition(pXmlDoc, aPath, "bookmark")); // not found
714 const int pos2 = getXPathPosition(pXmlDoc, aPath, "bookmark-start");
715 const int pos3 = getXPathPosition(pXmlDoc, aPath, "bookmark-end");
717 CPPUNIT_ASSERT_EQUAL(0, pos2); // found, and it is first
718 CPPUNIT_ASSERT_EQUAL(1, pos3); // found, and it is second
722 // 1. Open a new writer document
723 // 2. Enter the text "abcdef"
724 // 3. Select "abc"
725 // 4. Insert a bookmark on "abc" using Insert->Bookmark. Name the bookmark "test".
726 // 5. Open the navigator (F5)
727 // Select the bookmark "test" using the navigator.
728 // 6. Hit Del, thus deleting "abc" (The bookmark "test" is still there).
729 // 7. Call our macro
731 // Sub Main
732 // bookmark = ThisComponent.getBookmarks().getByName("test")
733 // bookmark.getAnchor().setString("abc")
734 // End Sub
736 // The text "abc" gets inserted inside the bookmark "test", and the document now contains the string "abcdef".
737 // 7. Save the document:
738 // <text:p text:style-name="Standard">
739 // <text:bookmark-start text:name="test"/>
740 // abc
741 // <text:bookmark-end text:name="test"/>
742 // def
743 // </text:p>
745 void SwUiWriterTest4::testRemoveBookmarkTextAndAddNew()
747 // create document
749 // create a text document with "abcdef"
750 SwDoc* pDoc = createSwDoc();
752 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
753 SwPaM aPaM(aIdx);
754 pDoc->getIDocumentContentOperations().InsertString(aPaM, "abcdef");
757 // mark "abc" with "testBookmark" bookmark
759 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
760 SwPaM aPaM(aIdx);
762 lcl_selectCharacters(aPaM, 0, 3);
763 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
764 sw::mark::IMark* pMark
765 = rIDMA.makeMark(aPaM, "testBookmark", IDocumentMarkAccess::MarkType::BOOKMARK,
766 ::sw::mark::InsertMode::New);
768 // verify
769 CPPUNIT_ASSERT(pMark->IsExpanded());
770 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
773 // remove text marked with bookmark
775 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
776 SwPaM aPaM(aIdx);
778 lcl_selectCharacters(aPaM, 0, 3);
779 pDoc->getIDocumentContentOperations().DeleteRange(aPaM);
781 // verify: bookmark is still exist
782 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
783 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
786 // write "abc" to area marked with "testBookmark" bookmark
788 // Get helper objects
789 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent,
790 uno::UNO_QUERY);
792 // Create cursor from bookmark
793 uno::Reference<text::XTextContent> xTextContent(
794 xBookmarksSupplier->getBookmarks()->getByName("testBookmark"), uno::UNO_QUERY);
795 uno::Reference<text::XTextRange> xRange = xTextContent->getAnchor();
796 CPPUNIT_ASSERT_EQUAL(OUString(""), xRange->getString());
798 // write "abc"
799 xRange->setString("abc");
801 // verify: bookmark is still exist
802 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
803 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
807 // save document
808 utl::TempFile aTempFile;
809 save("writer8", aTempFile);
811 // load only content.xml from the resaved document
812 if (xmlDocUniquePtr pXmlDoc = parseExportInternal(aTempFile.GetURL(), "content.xml"))
814 const OString aPath("/office:document-content/office:body/office:text/text:p");
816 CPPUNIT_ASSERT_ASSERTION_FAIL(getXPathPosition(pXmlDoc, aPath, "bookmark")); // not found
817 const int pos2 = getXPathPosition(pXmlDoc, aPath, "bookmark-start");
818 const int pos3 = getXPathPosition(pXmlDoc, aPath, "text");
819 const int pos4 = getXPathPosition(pXmlDoc, aPath, "bookmark-end");
821 CPPUNIT_ASSERT_EQUAL(0, pos2);
822 CPPUNIT_ASSERT_EQUAL(1, pos3);
823 CPPUNIT_ASSERT_EQUAL(2, pos4);
827 // 1. Load document:
828 // <text:p text:style-name="Standard">
829 // <text:bookmark-start text:name="test"/>
830 // <text:bookmark-end text:name="test"/>
831 // def
832 // </text:p>
834 // 2. Call our macro
836 // Sub Main
837 // bookmark = ThisComponent.getBookmarks().getByName("test")
838 // bookmark.getAnchor().setString("abc")
839 // End Sub
841 // The text "abc" gets inserted inside the bookmark "test", and the document now contains the string "abcdef".
842 // 3. Save the document:
843 // <text:p text:style-name="Standard">
844 // <text:bookmark text:name="test"/>
845 // abcdef
846 // </text:p>
848 void SwUiWriterTest4::testRemoveBookmarkTextAndAddNewAfterReload()
850 // load document
851 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "collapsed_bookmark.odt");
852 CPPUNIT_ASSERT(pDoc);
854 // write "abc" to area marked with "testBookmark" bookmark
856 // Get helper objects
857 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
859 // Create cursor from bookmark
860 uno::Reference<text::XTextContent> xTextContent(
861 xBookmarksSupplier->getBookmarks()->getByName("test"), uno::UNO_QUERY);
862 uno::Reference<text::XTextRange> xRange = xTextContent->getAnchor();
863 CPPUNIT_ASSERT_EQUAL(OUString(""), xRange->getString());
865 // write "abc"
866 xRange->setString("abc");
868 // verify: bookmark is still exist
869 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
870 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
873 // save original document
874 utl::TempFile aTempFile;
875 save("writer8", aTempFile);
877 // load only content.xml from the resaved document
878 if (xmlDocUniquePtr pXmlDoc = parseExportInternal(aTempFile.GetURL(), "content.xml"))
880 const OString aPath("/office:document-content/office:body/office:text/text:p");
882 const int pos1 = getXPathPosition(pXmlDoc, aPath, "bookmark");
883 const int pos2 = getXPathPosition(pXmlDoc, aPath, "text");
885 CPPUNIT_ASSERT_EQUAL(0, pos1);
886 CPPUNIT_ASSERT_EQUAL(1, pos2);
888 CPPUNIT_ASSERT_ASSERTION_FAIL(
889 getXPathPosition(pXmlDoc, aPath, "bookmark-start")); // not found
890 CPPUNIT_ASSERT_ASSERTION_FAIL(
891 getXPathPosition(pXmlDoc, aPath, "bookmark-end")); // not found
895 void SwUiWriterTest4::testTdf96961()
897 // Insert a page break.
898 SwDoc* pDoc = createSwDoc();
899 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
900 pWrtShell->InsertPageBreak();
902 // Enable hide whitespace mode.
903 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
904 aViewOptions.SetHideWhitespaceMode(true);
905 pWrtShell->ApplyViewOptions(aViewOptions);
907 calcLayout();
909 // Assert that the height of the last page is larger than the height of other pages.
910 sal_Int32 nOther = parseDump("/root/page[1]/infos/bounds", "height").toInt32();
911 sal_Int32 nLast = parseDump("/root/page[2]/infos/bounds", "height").toInt32();
912 CPPUNIT_ASSERT(nLast > nOther);
915 void SwUiWriterTest4::testTdf88453()
917 createSwDoc(DATA_DIRECTORY, "tdf88453.odt");
918 calcLayout();
919 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
920 // This was 0: the table does not fit the first page, but it wasn't split
921 // to continue on the second page.
922 assertXPath(pXmlDoc, "/root/page[2]/body/tab", 1);
925 void SwUiWriterTest4::testTdf88453Table()
927 createSwDoc(DATA_DIRECTORY, "tdf88453-table.odt");
928 calcLayout();
929 // This was 2: layout could not split the large outer table in the document
930 // into 3 pages.
931 CPPUNIT_ASSERT_EQUAL(3, getPages());
934 namespace
936 int checkShells(const SwDocShell* pSource, const SwDocShell* pDestination)
938 return int(SfxClassificationHelper::CheckPaste(pSource->getDocProperties(),
939 pDestination->getDocProperties()));
943 void SwUiWriterTest4::testClassificationPaste()
945 SwDocShell* pSourceShell = createSwDoc()->GetDocShell();
946 uno::Reference<lang::XComponent> xSourceComponent = mxComponent;
947 mxComponent.clear();
949 SwDocShell* pDestinationShell = createSwDoc()->GetDocShell();
951 // Not classified source, not classified destination.
952 CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::None),
953 checkShells(pSourceShell, pDestinationShell));
955 // Classified source, not classified destination.
956 uno::Sequence<beans::PropertyValue> aInternalOnly
957 = comphelper::InitPropertySequence({ { "Name", uno::makeAny(OUString("Internal Only")) } });
958 dispatchCommand(xSourceComponent, ".uno:ClassificationApply", aInternalOnly);
959 CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::TargetDocNotClassified),
960 checkShells(pSourceShell, pDestinationShell));
962 // Classified source and classified destination -- internal only has a higher level than confidential.
963 uno::Sequence<beans::PropertyValue> aConfidential
964 = comphelper::InitPropertySequence({ { "Name", uno::makeAny(OUString("Confidential")) } });
965 dispatchCommand(mxComponent, ".uno:ClassificationApply", aConfidential);
966 CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::DocClassificationTooLow),
967 checkShells(pSourceShell, pDestinationShell));
969 xSourceComponent->dispose();
972 void SwUiWriterTest4::testSmallCaps()
974 // Create a document, add some characters and select them.
975 createSwDoc();
976 SwDoc* pDoc = createSwDoc();
977 SwDocShell* pDocShell = pDoc->GetDocShell();
978 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
979 pWrtShell->Insert("text");
980 pWrtShell->SelAll();
982 // Dispatch the command to make them formatted small capitals.
983 dispatchCommand(mxComponent, ".uno:SmallCaps", {});
985 // This was css::style::CaseMap::NONE as the shell didn't handle the command.
986 CPPUNIT_ASSERT_EQUAL(css::style::CaseMap::SMALLCAPS,
987 getProperty<sal_Int16>(getRun(getParagraph(1), 1), "CharCaseMap"));
990 void SwUiWriterTest4::testTdf98987()
992 createSwDoc(DATA_DIRECTORY, "tdf98987.docx");
993 calcLayout();
994 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
995 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[2]/SdrObject", "name",
996 "Rectangle 1");
997 sal_Int32 nRectangle1
998 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[2]/bounds", "top")
999 .toInt32();
1000 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/SdrObject", "name",
1001 "Rectangle 2");
1002 sal_Int32 nRectangle2
1003 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/bounds", "top")
1004 .toInt32();
1005 CPPUNIT_ASSERT_GREATER(nRectangle1, nRectangle2);
1007 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[3]/SdrObject", "name",
1008 "Rectangle 3");
1009 sal_Int32 nRectangle3
1010 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[3]/bounds", "top")
1011 .toInt32();
1012 // This failed: the 3rd rectangle had a smaller "top" value than the 2nd one, it even overlapped with the 1st one.
1013 CPPUNIT_ASSERT_GREATER(nRectangle2, nRectangle3);
1016 void SwUiWriterTest4::testTdf99004()
1018 createSwDoc(DATA_DIRECTORY, "tdf99004.docx");
1019 calcLayout();
1020 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1021 sal_Int32 nTextbox1Top
1022 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "top").toInt32();
1023 sal_Int32 nTextBox1Height
1024 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "height").toInt32();
1025 sal_Int32 nTextBox1Bottom = nTextbox1Top + nTextBox1Height;
1027 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/SdrObject", "name",
1028 "Rectangle 2");
1029 sal_Int32 nRectangle2Top
1030 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/bounds", "top")
1031 .toInt32();
1032 // This was 3291 and 2531, should be now around 2472 and 2531, i.e. the two rectangles should not overlap anymore.
1033 CPPUNIT_ASSERT(nTextBox1Bottom < nRectangle2Top);
1036 void SwUiWriterTest4::testTdf84695()
1038 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf84695.odt");
1039 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1040 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
1041 SdrObject* pObject = pPage->GetObj(1);
1042 SwContact* pTextBox = static_cast<SwContact*>(pObject->GetUserCall());
1043 // First, make sure that pTextBox is a fly frame (textbox of a shape).
1044 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_FLYFRMFMT), pTextBox->GetFormat()->Which());
1046 // Then select it.
1047 pWrtShell->SelectObj(Point(), 0, pObject);
1049 // Now Enter + a key should add some text.
1050 SwXTextDocument* pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1051 CPPUNIT_ASSERT(pXTextDocument);
1052 pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RETURN);
1053 pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'a', 0);
1054 Scheduler::ProcessEventsToIdle();
1056 uno::Reference<text::XTextRange> xShape(getShape(1), uno::UNO_QUERY);
1057 // This was empty, Enter did not start the fly frame edit mode.
1058 CPPUNIT_ASSERT_EQUAL(OUString("a"), xShape->getString());
1061 void SwUiWriterTest4::testTdf84695NormalChar()
1063 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf84695.odt");
1064 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1065 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
1066 SdrObject* pObject = pPage->GetObj(1);
1067 SwContact* pTextBox = static_cast<SwContact*>(pObject->GetUserCall());
1068 // First, make sure that pTextBox is a fly frame (textbox of a shape).
1069 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_FLYFRMFMT), pTextBox->GetFormat()->Which());
1071 // Then select it.
1072 pWrtShell->SelectObj(Point(), 0, pObject);
1074 // Now pressing 'a' should add a character.
1075 SwXTextDocument* pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1076 CPPUNIT_ASSERT(pXTextDocument);
1077 pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 'a', 0);
1078 Scheduler::ProcessEventsToIdle();
1080 uno::Reference<text::XTextRange> xShape(getShape(1), uno::UNO_QUERY);
1081 // This was empty, pressing a normal character did not start the fly frame edit mode.
1082 CPPUNIT_ASSERT_EQUAL(OUString("a"), xShape->getString());
1085 void SwUiWriterTest4::testTdf84695Tab()
1087 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf84695-tab.odt");
1088 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1089 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
1090 SdrObject* pObject = pPage->GetObj(0);
1091 SwContact* pShape = static_cast<SwContact*>(pObject->GetUserCall());
1092 // First, make sure that pShape is a draw shape.
1093 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_DRAWFRMFMT), pShape->GetFormat()->Which());
1095 // Then select it.
1096 pWrtShell->SelectObj(Point(), 0, pObject);
1098 // Now pressing 'tab' should jump to the other shape.
1099 SwXTextDocument* pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1100 CPPUNIT_ASSERT(pXTextDocument);
1101 pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
1102 pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_TAB);
1103 Scheduler::ProcessEventsToIdle();
1105 // And finally make sure the selection has changed.
1106 const SdrMarkList& rMarkList = pWrtShell->GetDrawView()->GetMarkedObjectList();
1107 SwContact* pOtherShape
1108 = static_cast<SwContact*>(rMarkList.GetMark(0)->GetMarkedSdrObj()->GetUserCall());
1109 // This failed, 'tab' didn't do anything -> the selected shape was the same.
1110 CPPUNIT_ASSERT(pOtherShape != pShape);
1113 void SwUiWriterTest4::testTableStyleUndo()
1115 SwDoc* pDoc = createSwDoc();
1116 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
1118 sal_Int32 nStyleCount = pDoc->GetTableStyles().size();
1119 SwTableAutoFormat* pStyle = pDoc->MakeTableStyle("Test Style");
1120 SvxBrushItem aBackground(Color(0xFF00FF), RES_BACKGROUND);
1121 pStyle->GetBoxFormat(0).SetBackground(aBackground);
1123 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount + 1);
1124 rUndoManager.Undo();
1125 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount);
1126 rUndoManager.Redo();
1127 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount + 1);
1128 // check if attributes are preserved
1129 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1130 CPPUNIT_ASSERT(pStyle);
1131 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground));
1133 pDoc->DelTableStyle("Test Style");
1134 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount);
1135 rUndoManager.Undo();
1136 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount + 1);
1137 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1138 // check if attributes are preserved
1139 CPPUNIT_ASSERT(pStyle);
1140 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground));
1141 rUndoManager.Redo();
1142 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount);
1144 // undo delete so we can replace the style
1145 rUndoManager.Undo();
1146 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount + 1);
1147 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1148 CPPUNIT_ASSERT(pStyle);
1149 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground));
1151 SwTableAutoFormat aNewStyle("Test Style2");
1152 SvxBrushItem aBackground2(Color(0x00FF00), RES_BACKGROUND);
1153 aNewStyle.GetBoxFormat(0).SetBackground(aBackground2);
1155 pDoc->ChgTableStyle("Test Style", aNewStyle);
1156 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1157 CPPUNIT_ASSERT(pStyle);
1158 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground2));
1159 rUndoManager.Undo();
1160 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1161 CPPUNIT_ASSERT(pStyle);
1162 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground));
1163 rUndoManager.Redo();
1164 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1165 CPPUNIT_ASSERT(pStyle);
1166 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground2));
1169 void SwUiWriterTest4::testRedlineCopyPaste()
1171 // regressed in tdf#106746
1172 SwDoc* pDoc = createSwDoc();
1174 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
1175 SwPaM aPaM(aIdx);
1177 pDoc->getIDocumentContentOperations().InsertString(aPaM, "abzdezgh");
1178 SwTextNode* pTextNode = aPaM.GetNode().GetTextNode();
1180 // Turn on track changes, make changes, turn off track changes
1181 uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
1182 xPropertySet->setPropertyValue("RecordChanges", uno::makeAny(true));
1183 lcl_selectCharacters(aPaM, 2, 3);
1184 pDoc->getIDocumentContentOperations().ReplaceRange(aPaM, "c", false);
1185 lcl_selectCharacters(aPaM, 6, 7);
1186 pDoc->getIDocumentContentOperations().ReplaceRange(aPaM, "f", false);
1187 xPropertySet->setPropertyValue("RecordChanges", uno::makeAny(false));
1189 // Create the clipboard document.
1190 SwDoc aClipboard;
1191 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1193 // Select the whole content, copy, delete the original and paste the copied content
1194 pWrtShell->SelAll();
1195 pWrtShell->Copy(aClipboard);
1196 pWrtShell->Delete();
1197 pWrtShell->Paste(aClipboard);
1199 // With the bug this is "abzcdefgh", ie. contains the first deleted piece, too
1200 CPPUNIT_ASSERT_EQUAL(OUString("abcdefgh"), pTextNode->GetText());
1203 void SwUiWriterTest4::testTdf135260()
1205 SwDoc* pDoc = createSwDoc();
1206 SwDocShell* pDocShell = pDoc->GetDocShell();
1207 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
1208 pWrtShell->Insert("test");
1210 // Turn on track changes
1211 uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
1212 xPropertySet->setPropertyValue("RecordChanges", uno::makeAny(true));
1214 for (int i = 0; i < 4; i++)
1216 pWrtShell->DelLeft();
1219 SwEditShell* const pEditShell(pDoc->GetEditShell());
1220 // accept all redlines
1221 while (pEditShell->GetRedlineCount())
1222 pEditShell->AcceptRedline(0);
1224 // Without the fix in place, this test would have failed with
1225 // - Expected:
1226 // - Actual : tes
1227 CPPUNIT_ASSERT_EQUAL(OUString(""), getParagraph(1)->getString());
1230 void SwUiWriterTest4::testRedlineParam()
1232 // Create a document with minimal content.
1233 SwDoc* pDoc = createSwDoc();
1234 SwDocShell* pDocShell = pDoc->GetDocShell();
1235 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
1236 pWrtShell->Insert("middle");
1238 // Turn on track changes, and add changes to the start and end of the document.
1239 uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
1240 xPropertySet->setPropertyValue("RecordChanges", uno::makeAny(true));
1241 pWrtShell->StartOfSection();
1242 pWrtShell->Insert("aaa");
1243 pWrtShell->EndOfSection();
1244 pWrtShell->Insert("zzz");
1246 const SwRedlineTable& rTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
1247 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(2), rTable.size());
1249 // Select the first redline.
1250 pWrtShell->StartOfSection();
1251 uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
1252 { { "NextTrackedChange",
1253 uno::makeAny(o3tl::narrowing<sal_uInt16>(rTable[0]->GetId())) } }));
1254 dispatchCommand(mxComponent, ".uno:NextTrackedChange", aPropertyValues);
1255 Scheduler::ProcessEventsToIdle();
1256 SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
1257 // This failed: the parameter wasn't handled so the next change (zzz) was
1258 // selected, not the first one (aaa).
1259 CPPUNIT_ASSERT_EQUAL(OUString("aaa"), pShellCursor->GetText());
1261 // Select the second redline.
1262 pWrtShell->StartOfSection();
1263 aPropertyValues = comphelper::InitPropertySequence(
1264 { { "NextTrackedChange", uno::makeAny(o3tl::narrowing<sal_uInt16>(rTable[1]->GetId())) } });
1265 dispatchCommand(mxComponent, ".uno:NextTrackedChange", aPropertyValues);
1266 Scheduler::ProcessEventsToIdle();
1267 pShellCursor = pWrtShell->getShellCursor(false);
1268 CPPUNIT_ASSERT_EQUAL(OUString("zzz"), pShellCursor->GetText());
1270 // Move the cursor to the start again, and reject the second change.
1271 pWrtShell->StartOfSection();
1272 aPropertyValues = comphelper::InitPropertySequence(
1273 { { "RejectTrackedChange",
1274 uno::makeAny(o3tl::narrowing<sal_uInt16>(rTable[1]->GetId())) } });
1275 dispatchCommand(mxComponent, ".uno:RejectTrackedChange", aPropertyValues);
1276 Scheduler::ProcessEventsToIdle();
1277 pShellCursor = pWrtShell->getShellCursor(false);
1279 // This was 'middlezzz', the uno command rejected the redline under the
1280 // cursor, instead of the requested one.
1281 CPPUNIT_ASSERT_EQUAL(OUString("aaamiddle"),
1282 pShellCursor->GetPoint()->nNode.GetNode().GetTextNode()->GetText());
1285 void SwUiWriterTest4::testRedlineViewAuthor()
1287 // Test that setting an author at an SwView level has effect.
1289 // Create a document with minimal content.
1290 SwDoc* pDoc = createSwDoc();
1291 SwDocShell* pDocShell = pDoc->GetDocShell();
1292 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
1293 pWrtShell->Insert("middle");
1294 SwView* pView = pDocShell->GetView();
1295 const OUString aAuthor("A U. Thor");
1296 pView->SetRedlineAuthor(aAuthor);
1297 pDocShell->SetView(pView);
1299 // Turn on track changes, and add changes to the start of the document.
1300 uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
1301 xPropertySet->setPropertyValue("RecordChanges", uno::makeAny(true));
1302 pWrtShell->StartOfSection();
1303 pWrtShell->Insert("aaa");
1305 // Now assert that SwView::SetRedlineAuthor() had an effect.
1306 const SwRedlineTable& rTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
1307 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), rTable.size());
1308 SwRangeRedline* pRedline = rTable[0];
1309 // This was 'Unknown Author' instead of 'A U. Thor'.
1310 CPPUNIT_ASSERT_EQUAL(aAuthor, pRedline->GetAuthorString());
1312 // Insert a comment and assert that SwView::SetRedlineAuthor() affects this as well.
1313 dispatchCommand(mxComponent, ".uno:.uno:InsertAnnotation", {});
1314 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
1315 uno::Reference<container::XEnumerationAccess> xFieldsAccess(
1316 xTextFieldsSupplier->getTextFields());
1317 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
1318 uno::Reference<beans::XPropertySet> xField(xFields->nextElement(), uno::UNO_QUERY);
1319 // This was 'Unknown Author' instead of 'A U. Thor'.
1320 CPPUNIT_ASSERT_EQUAL(aAuthor, xField->getPropertyValue("Author").get<OUString>());
1322 //Reset the redline author after using it, otherwise, it might interfere with other unittests
1323 pView->SetRedlineAuthor("Unknown Author");
1324 pDocShell->SetView(pView);
1327 void SwUiWriterTest4::testTdf91292()
1329 createSwDoc(DATA_DIRECTORY, "tdf91292_paraBackground.docx");
1330 uno::Reference<beans::XPropertySet> xPropertySet(getParagraph(1), uno::UNO_QUERY);
1331 CPPUNIT_ASSERT_EQUAL_MESSAGE("Solid background color", drawing::FillStyle_SOLID,
1332 getProperty<drawing::FillStyle>(xPropertySet, "FillStyle"));
1333 CPPUNIT_ASSERT_EQUAL_MESSAGE("Background Color", static_cast<sal_Int32>(0x5C2D91),
1334 getProperty<sal_Int32>(xPropertySet, "FillColor"));
1336 // remove background color
1337 xPropertySet->setPropertyValue("FillStyle", uno::makeAny(drawing::FillStyle_NONE));
1339 // Save it and load it back.
1340 reload("Office Open XML Text", "tdf91292_paraBackground.docx");
1342 xPropertySet.set(getParagraph(1), uno::UNO_QUERY);
1343 CPPUNIT_ASSERT_EQUAL_MESSAGE("No background color", drawing::FillStyle_NONE,
1344 getProperty<drawing::FillStyle>(xPropertySet, "FillStyle"));
1347 void SwUiWriterTest4::testTdf78727()
1349 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf78727.docx");
1350 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
1351 // This was 1: make sure we don't loose the TextBox anchored inside the
1352 // table that is moved inside a text frame.
1353 CPPUNIT_ASSERT(SwTextBoxHelper::getCount(pPage) > 1);
1356 void SwUiWriterTest4::testRedlineTimestamp()
1358 // Test that a redline timestamp's second is not always 0.
1360 // Create a document with minimal content.
1361 SwDoc* pDoc = createSwDoc();
1362 SwDocShell* pDocShell = pDoc->GetDocShell();
1363 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
1364 pWrtShell->Insert("middle");
1366 // Turn on track changes, and add changes to the start and to the end of
1367 // the document.
1368 uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
1369 xPropertySet->setPropertyValue("RecordChanges", uno::makeAny(true));
1370 pWrtShell->StartOfSection();
1371 pWrtShell->Insert("aaa");
1372 osl::Thread::wait(std::chrono::seconds(1));
1373 pWrtShell->EndOfSection();
1374 pWrtShell->Insert("zzz");
1376 // Inserting additional characters at the start changed the table size to
1377 // 3, i.e. the first and the second "aaa" wasn't combined.
1378 pWrtShell->StartOfSection();
1379 pWrtShell->Insert("aaa");
1381 // Now assert that at least one of the seconds are not 0.
1382 const SwRedlineTable& rTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
1383 if (rTable.size() >= 2
1384 && rTable[0]->GetRedlineData().GetTimeStamp().GetMin()
1385 != rTable[1]->GetRedlineData().GetTimeStamp().GetMin())
1386 // The relatively rare case when waiting for a second also changes the minute.
1387 return;
1389 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(2), rTable.size());
1390 sal_uInt16 nSec1 = rTable[0]->GetRedlineData().GetTimeStamp().GetSec();
1391 sal_uInt16 nSec2 = rTable[1]->GetRedlineData().GetTimeStamp().GetSec();
1392 // This failed, seconds was always 0.
1393 CPPUNIT_ASSERT(nSec1 != 0 || nSec2 != 0);
1396 void SwUiWriterTest4::testCursorWindows()
1398 // Create a new document with one window.
1399 SwDoc* pDoc = createSwDoc();
1400 SwDocShell* pDocShell = pDoc->GetDocShell();
1401 SwWrtShell* pWrtShell1 = pDocShell->GetWrtShell();
1403 // Create a second view and type something.
1404 pDocShell->GetViewShell()->GetViewFrame()->GetDispatcher()->Execute(
1405 SID_NEWWINDOW, SfxCallMode::SYNCHRON | SfxCallMode::RECORD);
1406 SwWrtShell* pWrtShell2 = pDocShell->GetWrtShell();
1407 OUString aText("foo");
1408 pWrtShell2->Insert(aText);
1410 // Assert that only the cursor of the actual window move, not other cursors.
1411 SwShellCursor* pShellCursor1 = pWrtShell1->getShellCursor(false);
1412 SwShellCursor* pShellCursor2 = pWrtShell2->getShellCursor(false);
1413 // This was 3, not 0 -- cursor of the other window moved.
1414 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), pShellCursor1->Start()->nContent.GetIndex());
1415 CPPUNIT_ASSERT_EQUAL(aText.getLength(), pShellCursor2->Start()->nContent.GetIndex());
1418 void SwUiWriterTest4::testLandscape()
1420 // Set page orientation to landscape.
1421 SwDoc* pDoc = createSwDoc();
1422 uno::Sequence<beans::PropertyValue> aPropertyValues(
1423 comphelper::InitPropertySequence({ { "AttributePage.Landscape", uno::Any(true) } }));
1424 dispatchCommand(mxComponent, ".uno:AttributePage", aPropertyValues);
1425 Scheduler::ProcessEventsToIdle();
1427 // Assert that the document model was modified.
1428 SwDocShell* pDocShell = pDoc->GetDocShell();
1429 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
1430 size_t nPageDesc = pWrtShell->GetCurPageDesc();
1431 // This failed, page was still portrait.
1432 CPPUNIT_ASSERT(pWrtShell->GetPageDesc(nPageDesc).GetLandscape());
1435 void SwUiWriterTest4::testTdf95699()
1437 // Open the document with single FORMCHECKBOX field, select all and copy to clipboard
1438 // then check that clipboard contains the FORMCHECKBOX in text body.
1439 // Previously that failed.
1440 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf95699.odt");
1441 IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
1442 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount());
1443 SwDoc aClipboard;
1444 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1445 pWrtShell->SelAll();
1446 pWrtShell->Copy(aClipboard);
1447 pMarkAccess = aClipboard.getIDocumentMarkAccess();
1448 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount());
1449 ::sw::mark::IFieldmark* pFieldMark
1450 = pMarkAccess->getFieldmarkAfter(SwPosition(pDoc->GetNodes().GetEndOfExtras()));
1451 CPPUNIT_ASSERT_EQUAL(OUString("vnd.oasis.opendocument.field.FORMCHECKBOX"),
1452 pFieldMark->GetFieldname());
1455 void SwUiWriterTest4::testTdf104032()
1457 // Open the document with FORMCHECKBOX field, select it and copy to clipboard
1458 // Go to end of document and paste it, then undo
1459 // Previously that asserted in debug build.
1460 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf104032.odt");
1461 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
1462 SwDoc aClipboard;
1463 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1464 pWrtShell->StartOfSection();
1465 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
1466 pWrtShell->Copy(aClipboard);
1467 pWrtShell->EndOfSection();
1468 pWrtShell->Paste(aClipboard);
1469 rUndoManager.Undo();
1472 void SwUiWriterTest4::testTdf104440()
1474 createSwDoc(DATA_DIRECTORY, "tdf104440.odt");
1475 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1476 xmlXPathObjectPtr pXmlObj = getXPathNode(pXmlDoc, "//page[2]/body/txt/anchored");
1477 xmlNodeSetPtr pXmlNodes = pXmlObj->nodesetval;
1478 // This was 0: both Text Frames in the document were anchored to a
1479 // paragraph on page 1, while we expect that the second Text Frame is
1480 // anchored to a paragraph on page 2.
1481 CPPUNIT_ASSERT_EQUAL(1, xmlXPathNodeSetGetLength(pXmlNodes));
1482 xmlXPathFreeObject(pXmlObj);
1485 void SwUiWriterTest4::testTdf104425()
1487 createSwDoc(DATA_DIRECTORY, "tdf104425.odt");
1488 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1489 // The document contains one top-level 1-cell table with minimum row height set to 70 cm,
1490 // and the cell contents does not exceed the minimum row height.
1491 // It should span over 3 pages.
1492 assertXPath(pXmlDoc, "//page", 3);
1493 sal_Int32 nHeight1
1494 = getXPath(pXmlDoc, "//page[1]/body/tab/row/infos/bounds", "height").toInt32();
1495 sal_Int32 nHeight2
1496 = getXPath(pXmlDoc, "//page[2]/body/tab/row/infos/bounds", "height").toInt32();
1497 sal_Int32 nHeight3
1498 = getXPath(pXmlDoc, "//page[3]/body/tab/row/infos/bounds", "height").toInt32();
1499 double fSumHeight_mm = o3tl::convert<double>(nHeight1 + nHeight2 + nHeight3, o3tl::Length::twip,
1500 o3tl::Length::mm);
1501 CPPUNIT_ASSERT_DOUBLES_EQUAL(700.0, fSumHeight_mm, 0.05);
1504 // accepting change tracking gets stuck on change
1505 void SwUiWriterTest4::testTdf104814()
1507 SwDoc* const pDoc1(createSwDoc(DATA_DIRECTORY, "tdf104814.docx"));
1509 SwEditShell* const pEditShell(pDoc1->GetEditShell());
1511 // accept all redlines
1512 while (pEditShell->GetRedlineCount())
1513 pEditShell->AcceptRedline(0);
1516 // crash at redo of accepting table change tracking imported from DOCX
1517 void SwUiWriterTest4::testTableRedlineRedoCrash()
1519 SwDoc* const pDoc(createSwDoc(DATA_DIRECTORY, "TC-table-del-add.docx"));
1520 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
1522 // accept all redlines, Undo and accept all redlines again
1524 IDocumentRedlineAccess& rIDRA(pDoc->getIDocumentRedlineAccess());
1525 rIDRA.AcceptAllRedline(/*bAccept=*/true);
1527 rUndoManager.Undo();
1529 // without the fix, it crashes
1530 rIDRA.AcceptAllRedline(true);
1533 void SwUiWriterTest4::testTableRemoveHasTextChangesOnly()
1535 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "TC-table-del-add.docx");
1536 CPPUNIT_ASSERT(pDoc);
1537 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1538 CPPUNIT_ASSERT(pWrtShell);
1540 // disable Record Changes
1541 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
1542 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
1543 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1545 // 4 rows in Show Changes mode
1546 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1547 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1549 // Accepting tracked deletions results 3 rows
1550 IDocumentRedlineAccess& rIDRA(pDoc->getIDocumentRedlineAccess());
1551 rIDRA.AcceptAllRedline(/*bAccept=*/true);
1552 Scheduler::ProcessEventsToIdle();
1553 discardDumpedLayout();
1554 pXmlDoc = parseLayoutDump();
1555 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3);
1557 // Undo: 4 rows again
1558 pDoc->GetIDocumentUndoRedo().Undo();
1559 discardDumpedLayout();
1560 pXmlDoc = parseLayoutDump();
1561 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1563 // Accepting again: 3 rows (Undo of HasTextChangesOnly is correct)
1564 rIDRA.AcceptAllRedline(/*bAccept=*/true);
1565 Scheduler::ProcessEventsToIdle();
1566 discardDumpedLayout();
1567 pXmlDoc = parseLayoutDump();
1568 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3);
1570 // Undo: 4 rows again
1571 pDoc->GetIDocumentUndoRedo().Undo();
1572 discardDumpedLayout();
1573 pXmlDoc = parseLayoutDump();
1574 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1576 // Move the cursor after the redline, and insert some text without change tracking
1577 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1578 pWrtShell->Insert("X");
1580 // Accepting again: 4 rows (extra text keeps the deleted row)
1581 rIDRA.AcceptAllRedline(/*bAccept=*/true);
1582 Scheduler::ProcessEventsToIdle();
1583 discardDumpedLayout();
1584 pXmlDoc = parseLayoutDump();
1585 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1587 // delete the extra text with change tracking:
1588 // this resulted tracked row deletion again, because of missing
1589 // removing of HasTextChangeOnly SwTabLine property at accepting deletions previously
1591 // disable Record Changes
1592 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
1593 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
1594 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1596 dispatchCommand(mxComponent, ".uno:SwBackSpace", {});
1597 rIDRA.AcceptAllRedline(/*bAccept=*/true);
1598 Scheduler::ProcessEventsToIdle();
1599 discardDumpedLayout();
1600 pXmlDoc = parseLayoutDump();
1601 // This was 3
1602 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1605 void SwUiWriterTest4::testTableRemoveHasTextChangesOnly2()
1607 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "TC-table-del-add.docx");
1608 CPPUNIT_ASSERT(pDoc);
1609 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1610 CPPUNIT_ASSERT(pWrtShell);
1612 // disable Record Changes
1613 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
1614 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
1615 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1617 // check redline count
1618 SwEditShell* const pEditShell(pDoc->GetEditShell());
1619 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1621 // 4 rows in Show Changes mode
1622 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1623 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1625 // Move the cursor to the tracked insertion, after the first redline to activate the
1626 // acception of the whole table row insertion with a single "Accept Change"
1627 pWrtShell->Down(/*bSelect=*/false);
1628 pWrtShell->Down(/*bSelect=*/false);
1629 pWrtShell->Down(/*bSelect=*/false);
1630 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1631 Scheduler::ProcessEventsToIdle();
1632 dispatchCommand(mxComponent, ".uno:AcceptTrackedChange", {});
1633 Scheduler::ProcessEventsToIdle();
1634 discardDumpedLayout();
1635 pXmlDoc = parseLayoutDump();
1636 // Accepting tracked insertion results still 4 rows, but less redlines
1637 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1638 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(11), pEditShell->GetRedlineCount());
1640 // Undo: 4 rows again
1641 pDoc->GetIDocumentUndoRedo().Undo();
1642 discardDumpedLayout();
1643 pXmlDoc = parseLayoutDump();
1644 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1645 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1647 // To check Undo of HasTextChangesOnly reject the same row results 3 rows
1648 dispatchCommand(mxComponent, ".uno:Escape", {});
1649 dispatchCommand(mxComponent, ".uno:RejectTrackedChange", {});
1650 Scheduler::ProcessEventsToIdle();
1651 discardDumpedLayout();
1652 pXmlDoc = parseLayoutDump();
1653 // This was 4 (lost HasTextChangesOnly)
1654 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3);
1656 // Undo: 4 rows again
1657 pDoc->GetIDocumentUndoRedo().Undo();
1658 discardDumpedLayout();
1659 pXmlDoc = parseLayoutDump();
1660 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1661 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1664 void SwUiWriterTest4::testTdf147182_AcceptAllChangesInTableSelection()
1666 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "TC-table-del-add.docx");
1667 CPPUNIT_ASSERT(pDoc);
1668 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1669 CPPUNIT_ASSERT(pWrtShell);
1671 // check redline count
1672 SwEditShell* const pEditShell(pDoc->GetEditShell());
1673 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1675 // 4 rows in Show Changes mode
1676 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1677 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1679 // Select the first table to get a table selection
1680 dispatchCommand(mxComponent, ".uno:SelectAll", {});
1681 dispatchCommand(mxComponent, ".uno:SelectAll", {});
1682 dispatchCommand(mxComponent, ".uno:AcceptTrackedChange", {});
1683 Scheduler::ProcessEventsToIdle();
1684 discardDumpedLayout();
1685 pXmlDoc = parseLayoutDump();
1686 // Accepting tracked changes in the selected table results 3 rows
1687 // This was 4 (only text changes of the first selected cell were accepted)
1688 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3);
1689 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(8), pEditShell->GetRedlineCount());
1691 // Undo: 4 rows again
1692 pDoc->GetIDocumentUndoRedo().Undo();
1693 discardDumpedLayout();
1694 pXmlDoc = parseLayoutDump();
1695 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1696 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1698 // To check Undo of HasTextChangesOnly reject the same row results 3 rows
1699 dispatchCommand(mxComponent, ".uno:Escape", {});
1700 dispatchCommand(mxComponent, ".uno:SelectAll", {});
1701 dispatchCommand(mxComponent, ".uno:SelectAll", {});
1702 dispatchCommand(mxComponent, ".uno:RejectTrackedChange", {});
1703 Scheduler::ProcessEventsToIdle();
1704 discardDumpedLayout();
1705 pXmlDoc = parseLayoutDump();
1706 // This was 4 (only text changes of the first selected cell were rejected)
1707 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3);
1709 // Undo: 4 rows again
1710 pDoc->GetIDocumentUndoRedo().Undo();
1711 discardDumpedLayout();
1712 pXmlDoc = parseLayoutDump();
1713 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1714 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1717 void SwUiWriterTest4::testTdf66405()
1719 // Imported formula should have zero margins
1720 createSwDoc(DATA_DIRECTORY, "tdf66405.docx");
1721 uno::Reference<text::XTextEmbeddedObjectsSupplier> xEmbeddedObjectsSupplier(mxComponent,
1722 uno::UNO_QUERY);
1723 uno::Reference<container::XNameAccess> xEmbeddedObjects
1724 = xEmbeddedObjectsSupplier->getEmbeddedObjects();
1725 uno::Reference<beans::XPropertySet> xFormula;
1726 xEmbeddedObjects->getByName(xEmbeddedObjects->getElementNames()[0]) >>= xFormula;
1727 uno::Reference<beans::XPropertySet> xComponent;
1728 xFormula->getPropertyValue("Component") >>= xComponent;
1730 // Test embedded object's margins
1731 sal_Int32 nLeftMargin, nRightMargin, nTopMargin, nBottomMargin;
1732 xFormula->getPropertyValue("LeftMargin") >>= nLeftMargin;
1733 xFormula->getPropertyValue("RightMargin") >>= nRightMargin;
1734 xFormula->getPropertyValue("TopMargin") >>= nTopMargin;
1735 xFormula->getPropertyValue("BottomMargin") >>= nBottomMargin;
1736 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nLeftMargin);
1737 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nRightMargin);
1738 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nTopMargin);
1739 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nBottomMargin);
1741 // Test embedded object component's margins
1742 xComponent->getPropertyValue("LeftMargin") >>= nLeftMargin;
1743 xComponent->getPropertyValue("RightMargin") >>= nRightMargin;
1744 xComponent->getPropertyValue("TopMargin") >>= nTopMargin;
1745 xComponent->getPropertyValue("BottomMargin") >>= nBottomMargin;
1746 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nLeftMargin);
1747 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nRightMargin);
1748 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nTopMargin);
1749 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nBottomMargin);
1752 void SwUiWriterTest4::testTdf35021_tabOverMarginDemo()
1754 #if HAVE_MORE_FONTS
1755 createSwDoc(DATA_DIRECTORY, "tdf35021_tabOverMarginDemo.doc");
1756 calcLayout();
1757 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1758 // Tabs should go past the margin @ ~3381
1759 sal_Int32 nMargin = getXPath(pXmlDoc, "//body/txt[1]/infos/prtBounds", "width").toInt32();
1760 // left tab was 3381 because it got its own full line
1761 sal_Int32 nWidth
1762 = getXPath(pXmlDoc, "//SwLinePortion[@type='PortionType::TabLeft']", "width").toInt32();
1763 CPPUNIT_ASSERT_MESSAGE("Left Tab width is ~4479", nMargin < nWidth);
1764 // center tab was 842
1765 nWidth
1766 = getXPath(pXmlDoc, "//SwLinePortion[@type='PortionType::TabCenter']", "width").toInt32();
1767 CPPUNIT_ASSERT_MESSAGE("Center Tab width is ~3521", nMargin < nWidth);
1768 // right tab was probably the same as center tab.
1769 nWidth = getXPath(pXmlDoc, "//SwLinePortion[@type='PortionType::TabRight']", "width").toInt32();
1770 CPPUNIT_ASSERT_MESSAGE("Right Tab width is ~2907", sal_Int32(2500) < nWidth);
1771 // decimal tab was 266
1772 nWidth
1773 = getXPath(pXmlDoc, "//SwLinePortion[@type='PortionType::TabDecimal']", "width").toInt32();
1774 CPPUNIT_ASSERT_MESSAGE("Decimal Tab width is ~4096", nMargin < nWidth);
1775 #endif
1778 void SwUiWriterTest4::testTdf106701_tabOverMarginAutotab()
1780 createSwDoc(DATA_DIRECTORY, "tdf106701_tabOverMarginAutotab.doc");
1781 calcLayout();
1782 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1783 // The right margin is ~3378
1784 sal_Int32 nRightMargin = getXPath(pXmlDoc, "//body/txt[1]/infos/prtBounds", "width").toInt32();
1785 // Automatic tabstops should never be affected by tabOverMargin compatibility
1786 // The 1st line's width previously was ~9506
1787 sal_Int32 nWidth = getXPath(pXmlDoc, "//LineBreak[1]", "nWidth").toInt32();
1788 CPPUNIT_ASSERT_MESSAGE("1st line's width is less than the right margin", nWidth < nRightMargin);
1791 void SwUiWriterTest4::testTdf104492()
1793 createSwDoc(DATA_DIRECTORY, "tdf104492.docx");
1794 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1795 // The document should split table over 3 pages.
1796 assertXPath(pXmlDoc, "//page", 3);
1799 void SwUiWriterTest4::testTdf107025()
1801 // Tdf107025 - characters advance with wrong distance, so that
1802 // they are cluttered because of negative value or
1803 // break into multiple lines because of overflow.
1804 // The test document uses DFKAI-SB shipped with Windows.
1805 createSwDoc(DATA_DIRECTORY, "tdf107025.odt");
1806 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1807 // Verify the number of characters in each line.
1808 CPPUNIT_ASSERT_EQUAL(sal_Int32(1),
1809 getXPath(pXmlDoc, "(//SwLinePortion)[1]", "length").toInt32());
1810 CPPUNIT_ASSERT_EQUAL(sal_Int32(9),
1811 getXPath(pXmlDoc, "(//SwLinePortion)[2]", "length").toInt32());
1813 // Do the subsequent test only if the first line can be displayed,
1814 // in case that the required font does not exist.
1815 sal_Int32 nWidth1 = getXPath(pXmlDoc, "(//SwLinePortion)[1]", "width").toInt32();
1816 if (!nWidth1)
1817 return;
1819 CPPUNIT_ASSERT(!parseDump("(//SwLinePortion)[2]", "width").isEmpty());
1820 // Width of the second line is expected to be 9 times of the first.
1821 sal_Int32 nWidth2 = getXPath(pXmlDoc, "(//SwLinePortion)[2]", "width").toInt32();
1823 CPPUNIT_ASSERT_EQUAL(sal_Int32(9), nWidth2 / nWidth1);
1826 void SwUiWriterTest4::testTdf107362()
1828 createSwDoc(DATA_DIRECTORY, "tdf107362.odt");
1829 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1830 sal_Int32 nHeight
1831 = getXPath(pXmlDoc, "(//Text[@nType='PortionType::Text'])[1]", "nHeight").toInt32();
1832 sal_Int32 nWidth1
1833 = getXPath(pXmlDoc, "(//Text[@nType='PortionType::Text'])[1]", "nWidth").toInt32();
1834 sal_Int32 nWidth2
1835 = getXPath(pXmlDoc, "(//Text[@nType='PortionType::Text'])[2]", "nWidth").toInt32();
1836 sal_Int32 nLineWidth = getXPath(pXmlDoc, "//LineBreak", "nWidth").toInt32();
1837 sal_Int32 nKernWidth = nLineWidth - nWidth1 - nWidth2;
1838 // Test only if fonts are available
1839 if (nWidth1 > 500 && nWidth2 > 200)
1841 // Kern width should be smaller than 1/3 of the CJK font height.
1842 CPPUNIT_ASSERT(nKernWidth * 3 < nHeight);
1846 void SwUiWriterTest4::testTdf105417()
1848 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf105417.odt");
1849 CPPUNIT_ASSERT(pDoc);
1850 SwView* pView = pDoc->GetDocShell()->GetView();
1851 CPPUNIT_ASSERT(pView);
1852 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
1853 CPPUNIT_ASSERT(xHyphenator.is());
1854 // If there are no English hyphenation rules installed, we can't test
1855 // hyphenation.
1856 if (!xHyphenator->hasLocale(lang::Locale("en", "US", OUString())))
1857 return;
1859 uno::Reference<linguistic2::XLinguProperties> xLinguProperties(LinguMgr::GetLinguPropertySet());
1860 // Automatic hyphenation means not opening a dialog, but going ahead
1861 // non-interactively.
1862 xLinguProperties->setIsHyphAuto(true);
1863 SwHyphWrapper aWrap(pView, xHyphenator, /*bStart=*/false, /*bOther=*/true,
1864 /*bSelection=*/false);
1865 // This never returned, it kept trying to hyphenate the last word
1866 // (greenbacks) again and again.
1867 aWrap.SpellDocument();
1870 void SwUiWriterTest4::testTdf105625()
1872 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf105625.fodt");
1873 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1874 uno::Reference<uno::XComponentContext> xComponentContext(
1875 comphelper::getProcessComponentContext());
1876 // Ensure correct initial setting
1877 comphelper::ConfigurationHelper::writeDirectKey(
1878 xComponentContext, "org.openoffice.Office.Writer/", "Cursor/Option", "IgnoreProtectedArea",
1879 css::uno::Any(false), comphelper::EConfigurationModes::Standard);
1880 // We should be able to edit at positions adjacent to fields.
1881 // Check if the start and the end of the 1st paragraph are not protected
1882 // (they are adjacent to FORMCHECKBOX)
1883 pWrtShell->SttPara();
1884 CPPUNIT_ASSERT_EQUAL(false, pWrtShell->HasReadonlySel());
1885 pWrtShell->EndPara();
1886 CPPUNIT_ASSERT_EQUAL(false, pWrtShell->HasReadonlySel());
1887 // 2nd paragraph - FORMTEXT
1888 pWrtShell->Down(/*bSelect=*/false);
1889 // Check selection across FORMTEXT field boundary - must be read-only
1890 pWrtShell->SttPara();
1891 pWrtShell->Right(CRSR_SKIP_CHARS, /*bSelect=*/true, 1, /*bBasicCall=*/false);
1892 CPPUNIT_ASSERT_EQUAL(true, pWrtShell->HasReadonlySel());
1893 // Test deletion of whole field with single backspace
1894 // Previously it only removed right boundary of FORMTEXT, or failed removal at all
1895 const IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess();
1896 sal_Int32 nMarksBefore = pMarksAccess->getAllMarksCount();
1897 pWrtShell->EndPara();
1898 pWrtShell->DelLeft();
1899 sal_Int32 nMarksAfter = pMarksAccess->getAllMarksCount();
1900 CPPUNIT_ASSERT_EQUAL(nMarksBefore, nMarksAfter + 1);
1903 void SwUiWriterTest4::testTdf125151_protected()
1905 // Similar to testTdf105625 except this is in a protected section,
1906 // so read-only is already true when fieldmarks are considered.
1907 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf125151_protected.fodt");
1908 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1909 uno::Reference<uno::XComponentContext> xComponentContext(
1910 comphelper::getProcessComponentContext());
1911 // Ensure correct initial setting
1912 comphelper::ConfigurationHelper::writeDirectKey(
1913 xComponentContext, "org.openoffice.Office.Writer/", "Cursor/Option", "IgnoreProtectedArea",
1914 css::uno::Any(false), comphelper::EConfigurationModes::Standard);
1915 pWrtShell->Down(/*bSelect=*/false);
1916 // The cursor moved inside of the FieldMark textbox.
1917 CPPUNIT_ASSERT_EQUAL_MESSAGE("Readonly 1", false, pWrtShell->HasReadonlySel());
1918 // Move left to the start/definition of the textbox
1919 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1920 CPPUNIT_ASSERT_EQUAL_MESSAGE("Readonly 2", true, pWrtShell->HasReadonlySel());
1923 void SwUiWriterTest4::testTdf125151_protectedB()
1925 // Similar to testTdf105625 except this is protected with the Protect_Form compat setting
1926 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf125151_protectedB.fodt");
1927 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1928 uno::Reference<uno::XComponentContext> xComponentContext(
1929 comphelper::getProcessComponentContext());
1930 // Ensure correct initial setting
1931 comphelper::ConfigurationHelper::writeDirectKey(
1932 xComponentContext, "org.openoffice.Office.Writer/", "Cursor/Option", "IgnoreProtectedArea",
1933 css::uno::Any(false), comphelper::EConfigurationModes::Standard);
1934 // The cursor starts inside of the FieldMark textbox.
1935 CPPUNIT_ASSERT_EQUAL_MESSAGE("Readonly 1", false, pWrtShell->HasReadonlySel());
1936 // Move left to the start/definition of the textbox
1937 pWrtShell->Left(CRSR_SKIP_CHARS, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1938 CPPUNIT_ASSERT_EQUAL_MESSAGE("Readonly 2", true, pWrtShell->HasReadonlySel());
1941 void SwUiWriterTest4::testTdf106736()
1943 createSwDoc(DATA_DIRECTORY, "tdf106736-grid.odt");
1944 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1945 sal_Int32 nWidth
1946 = getXPath(pXmlDoc, "(//Text[@nType='PortionType::TabLeft'])[1]", "nWidth").toInt32();
1947 // In tdf106736, width of tab overflow so that it got
1948 // width value around 9200, expected value is around 103
1949 CPPUNIT_ASSERT_MESSAGE("Left Tab width is ~103", nWidth < 150);
1952 void SwUiWriterTest4::testMsWordCompTrailingBlanks()
1954 // The option is true in settings.xml
1955 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "MsWordCompTrailingBlanksTrue.odt");
1956 CPPUNIT_ASSERT_EQUAL(true, pDoc->getIDocumentSettingAccess().get(
1957 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS));
1958 calcLayout();
1959 // Check that trailing spaces spans have no width if option is enabled
1961 CPPUNIT_ASSERT_EQUAL(OUString(), parseDump("/root/page/body/txt[2]/Text[4]", "nWidth"));
1962 CPPUNIT_ASSERT_EQUAL(OUString(), parseDump("/root/page/body/txt[2]/Text[5]", "nWidth"));
1963 CPPUNIT_ASSERT_EQUAL(OUString(), parseDump("/root/page/body/txt[3]/Text[4]", "nWidth"));
1964 CPPUNIT_ASSERT_EQUAL(OUString(), parseDump("/root/page/body/txt[3]/Text[5]", "nWidth"));
1966 // The option is false in settings.xml
1967 pDoc = createSwDoc(DATA_DIRECTORY, "MsWordCompTrailingBlanksFalse.odt");
1968 CPPUNIT_ASSERT_EQUAL(false, pDoc->getIDocumentSettingAccess().get(
1969 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS));
1970 calcLayout();
1971 // Check that trailing spaces spans have width if option is disabled
1972 CPPUNIT_ASSERT(!parseDump("/root/page/body/txt[2]/Text[4]", "nWidth").isEmpty());
1973 CPPUNIT_ASSERT(!parseDump("/root/page/body/txt[2]/Text[5]", "nWidth").isEmpty());
1974 CPPUNIT_ASSERT(!parseDump("/root/page/body/txt[3]/Text[4]", "nWidth").isEmpty());
1975 CPPUNIT_ASSERT(!parseDump("/root/page/body/txt[3]/Text[5]", "nWidth").isEmpty());
1977 // MsWordCompTrailingBlanks option should be false by default in new documents
1978 pDoc = createSwDoc();
1979 CPPUNIT_ASSERT_EQUAL(false, pDoc->getIDocumentSettingAccess().get(
1980 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS));
1982 // The option should be true if a .docx, .doc or .rtf document is opened
1983 pDoc = createSwDoc(DATA_DIRECTORY, "MsWordCompTrailingBlanks.docx");
1984 CPPUNIT_ASSERT_EQUAL(true, pDoc->getIDocumentSettingAccess().get(
1985 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS));
1988 void SwUiWriterTest4::testCreateDocxAnnotation()
1990 createSwDoc();
1992 // insert an annotation with a text
1993 const OUString aSomeText("some text");
1994 uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({
1995 { "Text", uno::makeAny(aSomeText) },
1996 { "Author", uno::makeAny(OUString("me")) },
1998 dispatchCommand(mxComponent, ".uno:InsertAnnotation", aPropertyValues);
2000 // Save it as DOCX & load it again
2001 reload("Office Open XML Text", "create-docx-annotation.docx");
2003 // get the annotation
2004 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
2005 uno::Reference<container::XEnumerationAccess> xFieldsAccess(
2006 xTextFieldsSupplier->getTextFields());
2007 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
2008 uno::Reference<beans::XPropertySet> xField(xFields->nextElement(), uno::UNO_QUERY);
2010 // this was empty instead of "some text"
2011 CPPUNIT_ASSERT_EQUAL(aSomeText, xField->getPropertyValue("Content").get<OUString>());
2014 void SwUiWriterTest4::testTdf107976()
2016 // Create a document and create two transferables.
2017 SwDoc* pDoc = createSwDoc();
2018 SwWrtShell& rShell = *pDoc->GetDocShell()->GetWrtShell();
2019 rtl::Reference<SwTransferable> pTransferable(new SwTransferable(rShell));
2020 rtl::Reference<SwTransferable> pTransferable2(new SwTransferable(rShell));
2021 // Now close the document.
2022 mxComponent->dispose();
2023 mxComponent.clear();
2024 // This failed: the first shell had a pointer to the deleted shell.
2025 CPPUNIT_ASSERT(!pTransferable->GetShell());
2026 CPPUNIT_ASSERT(!pTransferable2->GetShell());
2029 void SwUiWriterTest4::testTdf58604()
2031 #ifdef _WIN32
2032 // Allow linebreak character follows hanging punctuation immediately instead of
2033 // breaking at the start of the next line.
2034 createSwDoc(DATA_DIRECTORY, "tdf58604.odt");
2035 CPPUNIT_ASSERT_EQUAL(
2036 OUString("PortionType::Break"),
2037 parseDump("(/root/page/body/txt/LineBreak[1]/preceding::Text)[last()]", "nType"));
2038 #endif
2041 void SwUiWriterTest4::testTdf112025()
2043 createSwDoc(DATA_DIRECTORY, "fdo112025.odt");
2044 const int numberOfParagraphs = getParagraphs();
2045 CPPUNIT_ASSERT_EQUAL(1, numberOfParagraphs);
2047 // get a page cursor
2048 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
2049 uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
2050 xModel->getCurrentController(), uno::UNO_QUERY);
2051 uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(),
2052 uno::UNO_QUERY);
2053 xCursor->jumpToEndOfPage();
2055 OUString insertFileid = m_directories.getURLFromSrc(DATA_DIRECTORY) + "fdo112025-insert.docx";
2056 uno::Sequence<beans::PropertyValue> aPropertyValues(
2057 comphelper::InitPropertySequence({ { "Name", uno::makeAny(insertFileid) } }));
2058 dispatchCommand(mxComponent, ".uno:InsertDoc", aPropertyValues);
2059 // something has been inserted + an additional paragraph
2060 CPPUNIT_ASSERT_GREATER(numberOfParagraphs, getParagraphs());
2062 uno::Reference<beans::XPropertySet> xStyle(getStyles("PageStyles")->getByName("Standard"),
2063 uno::UNO_QUERY);
2064 CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xStyle, "IsLandscape"));
2067 void SwUiWriterTest4::testTdf72942()
2069 createSwDoc(DATA_DIRECTORY, "fdo72942.docx");
2071 // get a page cursor
2072 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
2073 uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
2074 xModel->getCurrentController(), uno::UNO_QUERY);
2075 uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(),
2076 uno::UNO_QUERY);
2077 xCursor->jumpToEndOfPage();
2079 OUString insertFileid = m_directories.getURLFromSrc(DATA_DIRECTORY) + "fdo72942-insert.docx";
2080 uno::Sequence<beans::PropertyValue> aPropertyValues(
2081 comphelper::InitPropertySequence({ { "Name", uno::makeAny(insertFileid) } }));
2082 dispatchCommand(mxComponent, ".uno:InsertDoc", aPropertyValues);
2084 // check styles of paragraphs added from [fdo72942.docx]
2085 const uno::Reference<text::XTextRange> xRun1 = getRun(getParagraph(1), 1);
2086 CPPUNIT_ASSERT_EQUAL(OUString("Default English (Liberation serif) text with "),
2087 xRun1->getString());
2088 CPPUNIT_ASSERT_EQUAL(OUString("Liberation Serif"),
2089 getProperty<OUString>(xRun1, "CharFontName"));
2091 const uno::Reference<text::XTextRange> xRun2 = getRun(getParagraph(2), 1);
2092 CPPUNIT_ASSERT_EQUAL(OUString("Header 1 English text (Liberation sans) with "),
2093 xRun2->getString());
2094 CPPUNIT_ASSERT_EQUAL(OUString("Liberation Sans"), getProperty<OUString>(xRun2, "CharFontName"));
2096 // check styles of paragraphs added from [fdo72942-insert.docx]
2097 const uno::Reference<text::XTextRange> xRun3 = getRun(getParagraph(4), 1);
2098 CPPUNIT_ASSERT_EQUAL(OUString("Default German text (Calibri) with "), xRun3->getString());
2099 CPPUNIT_ASSERT_EQUAL(OUString("Liberation Serif"),
2100 getProperty<OUString>(xRun3, "CharFontName"));
2102 const uno::Reference<text::XTextRange> xRun4 = getRun(getParagraph(5), 1);
2103 CPPUNIT_ASSERT_EQUAL(OUString("Header 1 German text (Calibri Light) with "),
2104 xRun4->getString());
2105 CPPUNIT_ASSERT_EQUAL(OUString("Liberation Sans"), getProperty<OUString>(xRun4, "CharFontName"));
2108 void SwUiWriterTest4::testTdf114306()
2110 createSwDoc(DATA_DIRECTORY, "fdo114306.odt");
2111 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2113 // There are 2 long paragraphs in cell A1.
2114 // A part of paragraph 2 should flow over to the second page but
2115 // *not* the whole paragraph. There should be 2 paragraphs on
2116 // page 1 and 1 paragraph on page 2.
2117 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt", 2);
2118 assertXPath(pXmlDoc, "/root/page[2]/body/tab[1]/row[1]/cell[1]/txt", 1);
2121 void SwUiWriterTest4::testTdf114306_2()
2123 // tdf#114306 fix unexpected page break in row-spanned table
2124 // load regression document without writer crash
2125 createSwDoc(DATA_DIRECTORY, "fdo114306_2.odt");
2127 // correct number of pages
2128 CPPUNIT_ASSERT_EQUAL(4, getPages());
2131 void SwUiWriterTest4::testTdf113877_mergeDocs(const char* aDestDoc, const char* aInsertDoc)
2133 createSwDoc(DATA_DIRECTORY, aDestDoc);
2135 // set a page cursor into the end of the document
2136 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
2137 uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
2138 xModel->getCurrentController(), uno::UNO_QUERY);
2139 uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(),
2140 uno::UNO_QUERY);
2141 xCursor->jumpToEndOfPage();
2143 // insert the same document at current cursor position
2145 const OUString insertFileid
2146 = m_directories.getURLFromSrc(DATA_DIRECTORY) + OUString::createFromAscii(aInsertDoc);
2147 uno::Sequence<beans::PropertyValue> aPropertyValues(
2148 comphelper::InitPropertySequence({ { "Name", uno::makeAny(insertFileid) } }));
2149 dispatchCommand(mxComponent, ".uno:InsertDoc", aPropertyValues);
2153 // During insert of the document with list inside into the main document inside the list
2154 // we should merge both lists into one, when they have the same list properties
2155 void SwUiWriterTest4::testTdf113877()
2157 testTdf113877_mergeDocs("tdf113877_insert_numbered_list.odt",
2158 "tdf113877_insert_numbered_list.odt");
2160 const OUString listId1 = getProperty<OUString>(getParagraph(1), "ListId");
2161 const OUString listId4 = getProperty<OUString>(getParagraph(4), "ListId");
2162 const OUString listId5 = getProperty<OUString>(getParagraph(5), "ListId");
2163 const OUString listId6 = getProperty<OUString>(getParagraph(6), "ListId");
2164 const OUString listId7 = getProperty<OUString>(getParagraph(7), "ListId");
2166 // the initial list with 4 list items
2167 CPPUNIT_ASSERT_EQUAL(listId1, listId4);
2169 // the last of the first list, and the first of the inserted list
2170 CPPUNIT_ASSERT_EQUAL(listId4, listId5);
2171 CPPUNIT_ASSERT_EQUAL(listId5, listId6);
2172 CPPUNIT_ASSERT_EQUAL(listId6, listId7);
2175 // The same test as testTdf113877() but merging of two list should not be performed.
2176 void SwUiWriterTest4::testTdf113877NoMerge()
2178 testTdf113877_mergeDocs("tdf113877_insert_numbered_list.odt",
2179 "tdf113877_insert_numbered_list_abcd.odt");
2181 const OUString listId1 = getProperty<OUString>(getParagraph(1), "ListId");
2182 const OUString listId4 = getProperty<OUString>(getParagraph(4), "ListId");
2183 const OUString listId5 = getProperty<OUString>(getParagraph(5), "ListId");
2184 const OUString listId6 = getProperty<OUString>(getParagraph(6), "ListId");
2185 const OUString listId7 = getProperty<OUString>(getParagraph(7), "ListId");
2187 // the initial list with 4 list items
2188 CPPUNIT_ASSERT_EQUAL(listId1, listId4);
2190 // the last of the first list, and the first of the inserted list
2191 CPPUNIT_ASSERT(listId4 != listId5);
2192 CPPUNIT_ASSERT_EQUAL(listId5, listId6);
2193 CPPUNIT_ASSERT(listId6 != listId7);
2196 // Related test to testTdf113877(): Inserting into empty document a new document with list.
2197 // Insert position has NO its own paragraph style ("Standard" will be used).
2199 // Resulting document should be the same for following tests:
2200 // - testTdf113877_default_style()
2201 // - testTdf113877_Standard_style()
2203 void SwUiWriterTest4::testTdf113877_default_style()
2205 testTdf113877_mergeDocs("tdf113877_blank.odt", "tdf113877_insert_numbered_list_abcd.odt");
2207 const OUString listId1 = getProperty<OUString>(getParagraph(1), "ListId");
2208 const OUString listId2 = getProperty<OUString>(getParagraph(2), "ListId");
2209 const OUString listId3 = getProperty<OUString>(getParagraph(3), "ListId");
2211 CPPUNIT_ASSERT_EQUAL(listId1, listId2);
2212 CPPUNIT_ASSERT_EQUAL(listId1, listId3);
2215 // Related test to testTdf113877(): Inserting into empty document a new document with list.
2216 // Insert position has its own paragraph style derived from "Standard", but this style is the same as "Standard".
2218 // Resulting document should be the same for following tests:
2219 // - testTdf113877_default_style()
2220 // - testTdf113877_Standard_style()
2222 void SwUiWriterTest4::testTdf113877_Standard_style()
2224 testTdf113877_mergeDocs("tdf113877_blank_ownStandard.odt",
2225 "tdf113877_insert_numbered_list_abcd.odt");
2227 const OUString listId1 = getProperty<OUString>(getParagraph(1), "ListId");
2228 const OUString listId2 = getProperty<OUString>(getParagraph(2), "ListId");
2229 const OUString listId3 = getProperty<OUString>(getParagraph(3), "ListId");
2231 CPPUNIT_ASSERT_EQUAL(listId1, listId2);
2232 CPPUNIT_ASSERT_EQUAL(listId1, listId3);
2235 void SwUiWriterTest4::testTdf113877_blank_bold_on()
2237 testTdf113877_mergeDocs("tdf113877_blank_bold_on.odt",
2238 "tdf113877_insert_numbered_list_abcd.odt");
2240 const OUString listId1 = getProperty<OUString>(getParagraph(1), "ListId");
2241 const OUString listId2 = getProperty<OUString>(getParagraph(2), "ListId");
2242 const OUString listId3 = getProperty<OUString>(getParagraph(3), "ListId");
2244 CPPUNIT_ASSERT_EQUAL(listId1, listId2);
2245 CPPUNIT_ASSERT_EQUAL(listId1, listId3);
2248 void SwUiWriterTest4::testTdf113877_blank_bold_off()
2250 testTdf113877_mergeDocs("tdf113877_blank_bold_off.odt",
2251 "tdf113877_insert_numbered_list_abcd.odt");
2253 const OUString listId1 = getProperty<OUString>(getParagraph(1), "ListId");
2254 const OUString listId2 = getProperty<OUString>(getParagraph(2), "ListId");
2255 const OUString listId3 = getProperty<OUString>(getParagraph(3), "ListId");
2257 CPPUNIT_ASSERT_EQUAL(listId1, listId2);
2258 CPPUNIT_ASSERT_EQUAL(listId1, listId3);
2261 // just care that this does crash/assert
2262 void SwUiWriterTest4::testRhbz1810732()
2264 createSwDoc(DATA_DIRECTORY, "tdf113877_blank.odt");
2266 // set a page cursor into the end of the document
2267 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
2268 uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
2269 xModel->getCurrentController(), uno::UNO_QUERY);
2270 uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(),
2271 uno::UNO_QUERY);
2272 xCursor->jumpToEndOfPage();
2274 // insert the same document at current cursor position
2276 const OUString insertFileid
2277 = m_directories.getURLFromSrc(DATA_DIRECTORY) + "rhbz1810732.docx";
2278 uno::Sequence<beans::PropertyValue> aPropertyValues(
2279 comphelper::InitPropertySequence({ { "Name", uno::makeAny(insertFileid) } }));
2280 dispatchCommand(mxComponent, ".uno:InsertDoc", aPropertyValues);
2284 void SwUiWriterTest4::testTdf142157()
2286 createSwDoc();
2288 const OUString insertFileid = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf142157.odt";
2289 uno::Sequence<beans::PropertyValue> aPropertyValues(
2290 comphelper::InitPropertySequence({ { "Name", uno::makeAny(insertFileid) } }));
2291 dispatchCommand(mxComponent, ".uno:InsertDoc", aPropertyValues);
2293 uno::Reference<text::XTextSectionsSupplier> xTextSectionsSupplier(mxComponent, uno::UNO_QUERY);
2294 uno::Reference<container::XIndexAccess> xSections(xTextSectionsSupplier->getTextSections(),
2295 uno::UNO_QUERY);
2297 // Without the fix in place, this test would have failed with
2298 // - Expected: 1
2299 // - Actual : 0
2300 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
2303 void SwUiWriterTest4::testTdf116640()
2305 createSwDoc();
2307 uno::Sequence<beans::PropertyValue> aArgs(
2308 comphelper::InitPropertySequence({ { "Columns", uno::makeAny(sal_Int32(2)) } }));
2310 dispatchCommand(mxComponent, ".uno:InsertSection", aArgs);
2311 Scheduler::ProcessEventsToIdle();
2313 uno::Reference<text::XTextSectionsSupplier> xTextSectionsSupplier(mxComponent, uno::UNO_QUERY);
2314 uno::Reference<container::XIndexAccess> xSections(xTextSectionsSupplier->getTextSections(),
2315 uno::UNO_QUERY);
2316 uno::Reference<beans::XPropertySet> xTextSection(xSections->getByIndex(0), uno::UNO_QUERY);
2318 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
2320 uno::Reference<text::XTextColumns> xTextColumns
2321 = getProperty<uno::Reference<text::XTextColumns>>(xTextSection, "TextColumns");
2322 CPPUNIT_ASSERT_EQUAL(sal_Int16(2), xTextColumns->getColumnCount());
2324 dispatchCommand(mxComponent, ".uno:Undo", {});
2325 Scheduler::ProcessEventsToIdle();
2327 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xSections->getCount());
2329 dispatchCommand(mxComponent, ".uno:Redo", {});
2330 Scheduler::ProcessEventsToIdle();
2332 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
2334 dispatchCommand(mxComponent, ".uno:Undo", {});
2335 Scheduler::ProcessEventsToIdle();
2337 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xSections->getCount());
2340 void SwUiWriterTest4::testTdf108524()
2342 createSwDoc(DATA_DIRECTORY, "tdf108524.odt");
2343 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2344 // In total we expect two cells containing a section.
2345 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/section", 2);
2347 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell/section", 1);
2348 // This was 0, section wasn't split, instead it was only on the first page
2349 // and it was cut off.
2350 assertXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell/section", 1);
2353 void SwUiWriterTest4::testLinesInSectionInTable()
2355 // This is similar to testTdf108524(), but the page boundary now is not in
2356 // the middle of a multi-line paragraph: the section only contains oneliner
2357 // paragraphs instead.
2358 createSwDoc(DATA_DIRECTORY, "lines-in-section-in-table.odt");
2359 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2360 // In total we expect two cells containing a section.
2361 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/section", 2);
2363 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell/section", 1);
2364 // This was 0, section wasn't split, instead it was only on the first page
2365 // and it was cut off.
2366 assertXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell/section", 1);
2369 void SwUiWriterTest4::testLinesMoveBackwardsInSectionInTable()
2371 #if HAVE_MORE_FONTS
2372 // Assert that paragraph "4" is on page 1 and "5" is on page 2.
2373 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "lines-in-section-in-table.odt");
2374 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2375 assertXPath(pXmlDoc, "/root/page", 2);
2376 SwNodeOffset nPara4Node(
2377 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/section/txt[last()]", "txtNodeIndex")
2378 .toUInt32());
2379 CPPUNIT_ASSERT_EQUAL(OUString("4"), pDoc->GetNodes()[nPara4Node]->GetTextNode()->GetText());
2380 SwNodeOffset nPara5Node(
2381 getXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell[1]/section/txt[1]", "txtNodeIndex")
2382 .toUInt32());
2383 CPPUNIT_ASSERT_EQUAL(OUString("5"), pDoc->GetNodes()[nPara5Node]->GetTextNode()->GetText());
2385 // Remove paragraph "4".
2386 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2387 while (pWrtShell->GetCursor()->GetNode().GetIndex() < nPara4Node)
2388 pWrtShell->Down(/*bSelect=*/false);
2389 pWrtShell->EndPara();
2390 pWrtShell->Up(/*bSelect=*/true);
2391 pWrtShell->DelLeft();
2393 // Assert that paragraph "5" is now moved back to page 1 and is the last paragraph there.
2394 discardDumpedLayout();
2395 pXmlDoc = parseLayoutDump();
2396 SwNodeOffset nPage1LastNode(
2397 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/section/txt[last()]", "txtNodeIndex")
2398 .toUInt32());
2399 // This was "3", paragraph "4" was deleted, but "5" was not moved backwards from page 2.
2400 CPPUNIT_ASSERT_EQUAL(OUString("5"), pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
2401 #endif
2404 void SwUiWriterTest4::testTableInSection()
2406 #if HAVE_MORE_FONTS
2407 // The document has a section, containing a table that spans over 2 pages.
2408 createSwDoc(DATA_DIRECTORY, "table-in-sect.odt");
2409 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2410 // In total we expect 4 cells.
2411 assertXPath(pXmlDoc, "/root/page/body/section/tab/row/cell", 4);
2413 // Assert that on both pages the section contains 2 cells.
2414 assertXPath(pXmlDoc, "/root/page[1]/body/section/tab/row/cell", 2);
2415 assertXPath(pXmlDoc, "/root/page[2]/body/section/tab/row/cell", 2);
2416 #endif
2419 void SwUiWriterTest4::testTableInNestedSection()
2421 #if HAVE_MORE_FONTS
2422 // The document has a nested section, containing a table that spans over 2 pages.
2423 // This crashed the layout.
2424 createSwDoc(DATA_DIRECTORY, "rhbz739252-3.odt");
2425 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2426 // Make sure the table is inside a section and spans over 2 pages.
2427 assertXPath(pXmlDoc, "//page[1]//section/tab", 1);
2428 assertXPath(pXmlDoc, "//page[2]//section/tab", 1);
2429 #endif
2432 void SwUiWriterTest4::testTdf112741()
2434 #if HAVE_MORE_FONTS
2435 createSwDoc(DATA_DIRECTORY, "tdf112741.fodt");
2436 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2437 // This was 5 pages.
2438 assertXPath(pXmlDoc, "//page", 4);
2439 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell/section", 1);
2440 assertXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row/cell/section", 1);
2441 // This failed, 3rd page contained no sections.
2442 assertXPath(pXmlDoc, "//page[3]/body/tab/row/cell/tab/row/cell/section", 1);
2443 assertXPath(pXmlDoc, "//page[4]/body/tab/row/cell/tab/row/cell/section", 1);
2444 #endif
2447 void SwUiWriterTest4::testTdf112860()
2449 #if HAVE_MORE_FONTS
2450 // The document has a split section inside a nested table, and also a table
2451 // in the footer.
2452 // This crashed the layout.
2453 createSwDoc(DATA_DIRECTORY, "tdf112860.fodt");
2454 #endif
2457 void SwUiWriterTest4::testTdf113287()
2459 #if HAVE_MORE_FONTS
2460 createSwDoc(DATA_DIRECTORY, "tdf113287.fodt");
2461 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2462 assertXPath(pXmlDoc, "//page", 2);
2463 sal_uInt32 nCellTop
2464 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell[1]/infos/bounds", "top").toUInt32();
2465 sal_uInt32 nSectionTop
2466 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell[1]/section/infos/bounds", "top")
2467 .toUInt32();
2468 // Make sure section frame is inside the cell frame.
2469 // Expected greater than 4593, was only 3714.
2470 CPPUNIT_ASSERT_GREATER(nCellTop, nSectionTop);
2471 #endif
2474 void SwUiWriterTest4::testTdf113445()
2476 #if HAVE_MORE_FONTS
2477 // Force multiple-page view.
2478 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf113445.fodt");
2479 SwDocShell* pDocShell = pDoc->GetDocShell();
2480 SwView* pView = pDocShell->GetView();
2481 pView->SetViewLayout(/*nColumns=*/2, /*bBookMode=*/false);
2482 calcLayout();
2484 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2485 assertXPath(pXmlDoc, "//page", 2);
2486 sal_uInt32 nPage1Left = getXPath(pXmlDoc, "//page[1]/infos/bounds", "left").toUInt32();
2487 sal_uInt32 nPage2Left = getXPath(pXmlDoc, "//page[2]/infos/bounds", "left").toUInt32();
2488 // Make sure that page 2 is on the right hand side of page 1, not below it.
2489 CPPUNIT_ASSERT_GREATER(nPage1Left, nPage2Left);
2491 // Insert a new paragraph at the start of the document.
2492 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2493 pWrtShell->StartOfSection();
2494 pWrtShell->SplitNode();
2495 discardDumpedLayout();
2496 pXmlDoc = parseLayoutDump();
2498 // Make sure that Table2:C5 and Table2:D5 has its section frame inside the cell frame.
2499 sal_uInt32 nCell3Top
2500 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[3]/infos/bounds", "top")
2501 .toUInt32();
2502 sal_uInt32 nSection3Top
2503 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[3]/section/infos/bounds",
2504 "top")
2505 .toUInt32();
2506 CPPUNIT_ASSERT_GREATER(nCell3Top, nSection3Top);
2507 sal_uInt32 nCell4Top
2508 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[4]/infos/bounds", "top")
2509 .toUInt32();
2510 sal_uInt32 nSection4Top
2511 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[4]/section/infos/bounds",
2512 "top")
2513 .toUInt32();
2514 CPPUNIT_ASSERT_GREATER(nCell4Top, nSection4Top);
2515 // Also check if the two cells in the same row have the same top position.
2516 // This was 4818, expected only 1672.
2517 CPPUNIT_ASSERT_EQUAL(nCell3Top, nCell4Top);
2518 #endif
2521 void SwUiWriterTest4::testTdf113686()
2523 #if HAVE_MORE_FONTS
2524 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf113686.fodt");
2525 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2526 assertXPath(pXmlDoc, "/root/page", 2);
2527 SwNodeOffset nPage1LastNode(
2528 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/tab/row/cell[1]/txt[last()]",
2529 "txtNodeIndex")
2530 .toUInt32());
2531 CPPUNIT_ASSERT_EQUAL(OUString("Table2:A1-P10"),
2532 pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
2533 SwNodeOffset nPage2FirstNode(
2534 getXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell[1]/section/txt[1]", "txtNodeIndex")
2535 .toUInt32());
2536 CPPUNIT_ASSERT_EQUAL(OUString("Table1:A1"),
2537 pDoc->GetNodes()[nPage2FirstNode]->GetTextNode()->GetText());
2539 // Remove page 2.
2540 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2541 while (pWrtShell->GetCursor()->Start()->nNode.GetIndex() < nPage1LastNode)
2542 pWrtShell->Down(/*bSelect=*/false);
2543 pWrtShell->EndPara();
2544 for (int i = 0; i < 3; ++i)
2545 pWrtShell->Up(/*bSelect=*/true);
2546 pWrtShell->DelLeft();
2548 // Assert that the second page is removed.
2549 discardDumpedLayout();
2550 pXmlDoc = parseLayoutDump();
2551 // This was still 2, content from 2nd page was not moved.
2552 assertXPath(pXmlDoc, "/root/page", 1);
2553 #endif
2556 void SwUiWriterTest4::testTableInSectionInTable()
2558 #if HAVE_MORE_FONTS
2559 // The document has a table, containing a section, containing a nested
2560 // table.
2561 // This crashed the layout.
2562 createSwDoc(DATA_DIRECTORY, "i95698.odt");
2563 #endif
2566 void SwUiWriterTest4::testSectionInTableInTable()
2568 #if HAVE_MORE_FONTS
2569 // The document has a nested table, containing a multi-line section at a
2570 // page boundary.
2571 // This crashed the layout later in SwFrame::IsFootnoteAllowed().
2572 createSwDoc(DATA_DIRECTORY, "tdf112109.fodt");
2573 #endif
2576 void SwUiWriterTest4::testSectionInTableInTable2()
2578 #if HAVE_MORE_FONTS
2579 createSwDoc(DATA_DIRECTORY, "split-section-in-nested-table.fodt");
2580 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2581 sal_uInt32 nSection1
2582 = getXPath(pXmlDoc, "//page[1]//body/tab/row/cell/tab/row/cell/section", "id").toUInt32();
2583 sal_uInt32 nSection1Follow
2584 = getXPath(pXmlDoc, "//page[1]//body/tab/row/cell/tab/row/cell/section", "follow")
2585 .toUInt32();
2586 // This failed, the section wasn't split inside a nested table.
2587 sal_uInt32 nSection2
2588 = getXPath(pXmlDoc, "//page[2]//body/tab/row/cell/tab/row/cell/section", "id").toUInt32();
2589 sal_uInt32 nSection2Precede
2590 = getXPath(pXmlDoc, "//page[2]//body/tab/row/cell/tab/row/cell/section", "precede")
2591 .toUInt32();
2593 // Make sure that the first's follow and the second's precede is correct.
2594 CPPUNIT_ASSERT_EQUAL(nSection2, nSection1Follow);
2595 CPPUNIT_ASSERT_EQUAL(nSection1, nSection2Precede);
2596 #endif
2599 void SwUiWriterTest4::testSectionInTableInTable3()
2601 #if HAVE_MORE_FONTS
2602 createSwDoc(DATA_DIRECTORY, "tdf113153.fodt");
2604 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
2605 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
2606 uno::UNO_QUERY);
2607 uno::Reference<container::XNamed> xTable(xTables->getByIndex(1), uno::UNO_QUERY);
2608 CPPUNIT_ASSERT_EQUAL(OUString("Table16"), xTable->getName());
2610 uno::Reference<text::XTextTable> xRowSupplier(xTable, uno::UNO_QUERY);
2611 uno::Reference<table::XTableRows> xRows = xRowSupplier->getRows();
2612 uno::Reference<beans::XPropertySet> xRow(xRows->getByIndex(1), uno::UNO_QUERY);
2613 xRow->setPropertyValue("IsSplitAllowed", uno::makeAny(true));
2614 // This never returned.
2615 calcLayout();
2617 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2618 sal_uInt32 nTable1 = getXPath(pXmlDoc, "//page[1]//body/tab", "id").toUInt32();
2619 sal_uInt32 nTable1Follow = getXPath(pXmlDoc, "//page[1]//body/tab", "follow").toUInt32();
2620 sal_uInt32 nTable2 = getXPath(pXmlDoc, "//page[2]//body/tab", "id").toUInt32();
2621 sal_uInt32 nTable2Precede = getXPath(pXmlDoc, "//page[2]//body/tab", "precede").toUInt32();
2622 sal_uInt32 nTable2Follow = getXPath(pXmlDoc, "//page[2]//body/tab", "follow").toUInt32();
2623 sal_uInt32 nTable3 = getXPath(pXmlDoc, "//page[3]//body/tab", "id").toUInt32();
2624 sal_uInt32 nTable3Precede = getXPath(pXmlDoc, "//page[3]//body/tab", "precede").toUInt32();
2626 // Make sure the outer table frames are linked together properly.
2627 CPPUNIT_ASSERT_EQUAL(nTable2, nTable1Follow);
2628 CPPUNIT_ASSERT_EQUAL(nTable1, nTable2Precede);
2629 CPPUNIT_ASSERT_EQUAL(nTable3, nTable2Follow);
2630 CPPUNIT_ASSERT_EQUAL(nTable2, nTable3Precede);
2631 #endif
2634 void SwUiWriterTest4::testSectionInTableInTable4()
2636 #if HAVE_MORE_FONTS
2637 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf113520.fodt");
2638 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2639 assertXPath(pXmlDoc, "/root/page", 3);
2640 SwNodeOffset nPage1LastNode(
2641 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/tab/row/cell[1]/section/txt[last()]",
2642 "txtNodeIndex")
2643 .toUInt32());
2644 CPPUNIT_ASSERT_EQUAL(OUString("Section1:P10"),
2645 pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
2646 SwNodeOffset nPage3FirstNode(
2647 getXPath(pXmlDoc, "/root/page[3]/body/tab/row/cell[1]/tab/row/cell[1]/section/txt[1]",
2648 "txtNodeIndex")
2649 .toUInt32());
2650 CPPUNIT_ASSERT_EQUAL(OUString("Section1:P23"),
2651 pDoc->GetNodes()[nPage3FirstNode]->GetTextNode()->GetText());
2653 // Remove page 2.
2654 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2655 while (pWrtShell->GetCursor()->Start()->nNode.GetIndex() < nPage1LastNode)
2656 pWrtShell->Down(/*bSelect=*/false);
2657 pWrtShell->EndPara();
2658 while (pWrtShell->GetCursor()->End()->nNode.GetIndex() < nPage3FirstNode)
2659 pWrtShell->Down(/*bSelect=*/true);
2660 pWrtShell->EndPara(/*bSelect=*/true);
2661 pWrtShell->DelLeft();
2663 // Assert that the page is removed.
2664 discardDumpedLayout();
2665 pXmlDoc = parseLayoutDump();
2666 // This was 3, page 2 was emptied, but it wasn't removed.
2667 assertXPath(pXmlDoc, "/root/page", 2);
2669 // Make sure the outer table frames are linked together properly.
2670 sal_uInt32 nTable1 = getXPath(pXmlDoc, "//page[1]//body/tab", "id").toUInt32();
2671 sal_uInt32 nTable1Follow = getXPath(pXmlDoc, "//page[1]//body/tab", "follow").toUInt32();
2672 sal_uInt32 nTable2 = getXPath(pXmlDoc, "//page[2]//body/tab", "id").toUInt32();
2673 sal_uInt32 nTable2Precede = getXPath(pXmlDoc, "//page[2]//body/tab", "precede").toUInt32();
2674 CPPUNIT_ASSERT_EQUAL(nTable2, nTable1Follow);
2675 CPPUNIT_ASSERT_EQUAL(nTable1, nTable2Precede);
2676 #endif
2679 void SwUiWriterTest4::testTdf112160()
2681 #if HAVE_MORE_FONTS
2682 // Assert that the A2 cell is on page 1.
2683 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf112160.fodt");
2684 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2685 SwNodeOffset nA2CellNode(getXPath(pXmlDoc,
2686 "/root/page[1]/body/tab/row[2]/cell[1]/section/txt[last()]",
2687 "txtNodeIndex")
2688 .toUInt32());
2689 CPPUNIT_ASSERT_EQUAL(OUString("Table1.A2"),
2690 pDoc->GetNodes()[nA2CellNode]->GetTextNode()->GetText());
2692 // Append a new paragraph to the end of the A2 cell.
2693 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2694 while (pWrtShell->GetCursor()->GetNode().GetIndex() < nA2CellNode)
2695 pWrtShell->Down(/*bSelect=*/false);
2696 pWrtShell->EndPara();
2697 pWrtShell->SplitNode();
2699 // Assert that after A2 got extended, D2 stays on page 1.
2700 discardDumpedLayout();
2701 pXmlDoc = parseLayoutDump();
2702 sal_uInt32 nD2CellNode
2703 = getXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[last()]/section/txt[last()]",
2704 "txtNodeIndex")
2705 .toUInt32();
2706 // This was Table1.C2, Table1.D2 was moved to the next page, unexpected.
2707 CPPUNIT_ASSERT_EQUAL(OUString("Table1.D2"),
2708 pDoc->GetNodes()[SwNodeOffset(nD2CellNode)]->GetTextNode()->GetText());
2709 #endif
2712 void SwUiWriterTest4::testTdf114536()
2714 // This crashed in SwTextFormatter::MergeCharacterBorder() due to a
2715 // use after free.
2716 createSwDoc(DATA_DIRECTORY, "tdf114536.odt");
2719 void SwUiWriterTest4::testParagraphOfTextRange()
2721 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "paragraph-of-text-range.odt");
2723 // Enter the table.
2724 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2725 pWrtShell->Down(/*bSelect=*/false);
2726 CPPUNIT_ASSERT(pWrtShell->IsCursorInTable());
2727 // Enter the section.
2728 pWrtShell->Down(/*bSelect=*/false);
2729 CPPUNIT_ASSERT(pWrtShell->IsDirectlyInSection());
2731 // Assert that we get the right paragraph object.
2732 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
2733 uno::Reference<text::XTextViewCursorSupplier> xController(xModel->getCurrentController(),
2734 uno::UNO_QUERY);
2735 uno::Reference<text::XTextRange> xViewCursor = xController->getViewCursor();
2736 // This failed as there were no TextParagraph property.
2737 auto xParagraph
2738 = getProperty<uno::Reference<text::XTextRange>>(xViewCursor->getStart(), "TextParagraph");
2739 CPPUNIT_ASSERT_EQUAL(OUString("In section"), xParagraph->getString());
2742 void SwUiWriterTest4::testTdf99689TableOfContents()
2744 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf99689.odt");
2745 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2746 pWrtShell->GotoNextTOXBase();
2747 const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
2748 pWrtShell->UpdateTableOf(*pTOXBase);
2749 SwCursorShell* pShell(pDoc->GetEditShell());
2750 SwTextNode* pTitleNode = pShell->GetCursor()->GetNode().GetTextNode();
2751 SwNodeIndex aIdx(*pTitleNode);
2752 // skip the title
2753 pDoc->GetNodes().GoNext(&aIdx);
2755 // skip the first header. No attributes there.
2756 // next node should contain superscript
2757 SwTextNode* pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
2758 CPPUNIT_ASSERT(pNext->HasHints());
2759 sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
2760 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
2762 // next node should contain subscript
2763 pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
2764 CPPUNIT_ASSERT(pNext->HasHints());
2765 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
2766 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
2769 void SwUiWriterTest4::testTdf99689TableOfFigures()
2771 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf99689_figures.odt");
2772 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2773 pWrtShell->GotoNextTOXBase();
2774 const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
2775 pWrtShell->UpdateTableOf(*pTOXBase);
2776 SwCursorShell* pShell(pDoc->GetEditShell());
2777 SwTextNode* pTitleNode = pShell->GetCursor()->GetNode().GetTextNode();
2778 SwNodeIndex aIdx(*pTitleNode);
2780 // skip the title
2781 // next node should contain subscript
2782 SwTextNode* pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
2783 CPPUNIT_ASSERT(pNext->HasHints());
2784 sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
2785 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
2787 // next node should contain superscript
2788 pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
2789 CPPUNIT_ASSERT(pNext->HasHints());
2790 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
2791 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
2794 void SwUiWriterTest4::testTdf99689TableOfTables()
2796 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf99689_tables.odt");
2797 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2798 pWrtShell->GotoNextTOXBase();
2799 const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
2800 pWrtShell->UpdateTableOf(*pTOXBase);
2801 SwCursorShell* pShell(pDoc->GetEditShell());
2802 SwTextNode* pTitleNode = pShell->GetCursor()->GetNode().GetTextNode();
2803 SwNodeIndex aIdx(*pTitleNode);
2805 // skip the title
2806 // next node should contain superscript
2807 SwTextNode* pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
2808 CPPUNIT_ASSERT(pNext->HasHints());
2809 sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
2810 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
2812 // next node should contain subscript
2813 pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
2814 CPPUNIT_ASSERT(pNext->HasHints());
2815 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
2816 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
2819 // tdf#112448: Fix: take correct line height
2821 // When line metrics is not calculated we need to call CalcRealHeight()
2822 // before usage of the Height() and GetRealHeight().
2823 void SwUiWriterTest4::testTdf112448()
2825 createSwDoc(DATA_DIRECTORY, "tdf112448.odt");
2827 // check actual number of line breaks in the paragraph
2828 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2829 assertXPath(pXmlDoc, "/root/page/body/txt/LineBreak", 2);
2832 void SwUiWriterTest4::testTdf113790()
2834 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf113790.docx");
2835 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2836 // Create the clipboard document.
2837 SwDoc aClipboard;
2838 aClipboard.SetClipBoard(true);
2840 // Go to fourth line - to "ABCD" bulleted list item
2841 pWrtShell->Down(/*bSelect=*/false, 4);
2842 pWrtShell->SelPara(nullptr);
2843 CPPUNIT_ASSERT_EQUAL(OUString("ABCD"), pWrtShell->GetSelText());
2844 pWrtShell->Copy(aClipboard);
2846 // Go down to next-to-last (empty) line above "Title3"
2847 pWrtShell->Down(/*bSelect=*/false, 4);
2848 pWrtShell->Paste(aClipboard);
2850 // Save it as DOCX & load it again
2851 reload("Office Open XML Text", "tdf113790.docx");
2852 CPPUNIT_ASSERT(dynamic_cast<SwXTextDocument*>(mxComponent.get()));
2855 void SwUiWriterTest4::testTdf108048()
2857 createSwDoc();
2859 uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({
2860 { "Kind", uno::makeAny(sal_Int16(3)) },
2861 { "TemplateName", uno::makeAny(OUString("Default Page Style")) },
2862 { "PageNumber",
2863 uno::makeAny(sal_uInt16(6)) }, // Even number to avoid auto-inserted blank page
2864 { "PageNumberFilled", uno::makeAny(true) },
2866 dispatchCommand(mxComponent, ".uno:InsertBreak", aPropertyValues);
2867 CPPUNIT_ASSERT_EQUAL(2, getParagraphs());
2868 CPPUNIT_ASSERT_EQUAL(2, getPages());
2870 // The inserted page must have page number set to 6
2871 uno::Reference<text::XTextRange> xPara = getParagraph(2);
2872 sal_uInt16 nPageNumber = getProperty<sal_uInt16>(xPara, "PageNumberOffset");
2873 CPPUNIT_ASSERT_EQUAL(sal_uInt16(6), nPageNumber);
2876 void SwUiWriterTest4::testTdf113481()
2878 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf113481-IVS.odt");
2879 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2881 // One backspace should completely remove the CJK ideograph variation sequence
2882 pWrtShell->EndPara();
2883 // Before: U+8FBA U+E0102. After: empty
2884 pWrtShell->DelLeft();
2885 const uno::Reference<text::XTextRange> xPara1 = getParagraph(1);
2886 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xPara1->getString().getLength());
2888 // In case that weak script is treated as CJK script, remove one character.
2889 pWrtShell->Down(false);
2890 pWrtShell->EndPara();
2891 // Before: U+4E2D U+2205 U+FE00. After: U+4E2D U+2205
2892 if (pWrtShell->GetScriptType() == SvtScriptType::ASIAN)
2894 pWrtShell->DelLeft();
2895 const uno::Reference<text::XTextRange> xPara2 = getParagraph(2);
2896 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xPara2->getString().getLength());
2897 CPPUNIT_ASSERT_EQUAL(u'\x2205', xPara2->getString()[1]);
2900 // Characters of other scripts, remove one character.
2901 pWrtShell->Down(false);
2902 pWrtShell->EndPara();
2903 // Before: U+1820 U+180B. After: U+1820
2904 pWrtShell->DelLeft();
2905 const uno::Reference<text::XTextRange> xPara3 = getParagraph(3);
2906 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xPara3->getString().getLength());
2907 CPPUNIT_ASSERT_EQUAL(u'\x1820', xPara3->getString()[0]);
2910 void SwUiWriterTest4::testTdf115013()
2912 const OUString sColumnName("Name with spaces, \"quotes\" and \\backslashes");
2914 utl::TempFile aTempDir(nullptr, true);
2915 aTempDir.EnableKillingFile();
2916 const OUString aWorkDir = aTempDir.GetURL();
2918 //create new writer document
2919 SwDoc* pDoc = createSwDoc();
2922 // Load and register data source
2923 const OUString aDataSourceURI(m_directories.getURLFromSrc(DATA_DIRECTORY)
2924 + "datasource.ods");
2925 OUString sDataSource = SwDBManager::LoadAndRegisterDataSource(aDataSourceURI, &aWorkDir);
2926 CPPUNIT_ASSERT(!sDataSource.isEmpty());
2928 // Insert a new field type for the mailmerge field
2929 SwDBData aDBData;
2930 aDBData.sDataSource = sDataSource;
2931 aDBData.sCommand = "Sheet1";
2932 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2933 CPPUNIT_ASSERT(pWrtShell);
2934 SwDBFieldType* pFieldType = static_cast<SwDBFieldType*>(
2935 pWrtShell->InsertFieldType(SwDBFieldType(pDoc, sColumnName, aDBData)));
2936 CPPUNIT_ASSERT(pFieldType);
2938 // Insert the field into document
2939 SwDBField aField(pFieldType);
2940 pWrtShell->InsertField2(aField);
2942 // Save it as DOCX & load it again
2943 reload("Office Open XML Text", "mm-field.docx");
2945 auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2946 CPPUNIT_ASSERT(pXTextDocument);
2947 pDoc = pXTextDocument->GetDocShell()->GetDoc();
2948 CPPUNIT_ASSERT(pDoc);
2949 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2950 CPPUNIT_ASSERT(pWrtShell);
2951 SwPaM* pCursor = pDoc->GetEditShell()->GetCursor();
2952 CPPUNIT_ASSERT(pCursor);
2954 // Get the field at the beginning of the document
2955 SwDBField* pField = dynamic_cast<SwDBField*>(SwCursorShell::GetFieldAtCursor(pCursor, true));
2956 CPPUNIT_ASSERT(pField);
2957 OUString sColumn = static_cast<SwDBFieldType*>(pField->GetTyp())->GetColumnName();
2958 // The column name must come correct after round trip
2959 CPPUNIT_ASSERT_EQUAL(sColumnName, sColumn);
2962 void SwUiWriterTest4::testTdf115065()
2964 // In the document, the tables have table style assigned
2965 // Source table (first one) has two rows;
2966 // destination (second one) has only one row
2967 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf115065.odt");
2968 CPPUNIT_ASSERT(pDoc);
2969 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2970 CPPUNIT_ASSERT(pWrtShell);
2972 pWrtShell->GotoTable("Table2");
2973 SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
2974 // Destination point is the middle of the first cell of second table
2975 Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
2977 pWrtShell->GotoTable("Table1");
2978 aRect = pWrtShell->GetCurrFrame()->getFrameArea();
2979 // Source point is the middle of the first cell of first table
2980 Point ptFrom(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
2982 pWrtShell->SelTableCol();
2983 // The copy operation (or closing document after that) segfaulted
2984 pWrtShell->Copy(*pWrtShell, ptFrom, ptTo);
2987 void SwUiWriterTest4::testTdf84806_MovingMultipleTableRows()
2989 // Moving of multiple table rows.
2990 // Source table (first one) has two rows;
2991 // destination (second one) has only one row
2992 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf115065.odt");
2993 CPPUNIT_ASSERT(pDoc);
2994 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2995 CPPUNIT_ASSERT(pWrtShell);
2997 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
2998 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
2999 uno::UNO_QUERY);
3000 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
3001 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
3002 CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
3003 CPPUNIT_ASSERT(xTableNames->hasByName("Table2"));
3004 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName("Table1"), uno::UNO_QUERY);
3005 uno::Reference<text::XTextTable> xTable2(xTableNames->getByName("Table2"), uno::UNO_QUERY);
3006 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
3007 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2->getRows()->getCount());
3009 // without redlining
3010 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
3011 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
3013 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
3015 pWrtShell->GotoTable("Table2");
3016 SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
3017 // Destination point is the middle of the first cell of second table
3018 Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
3020 // Move rows of the first table into the second table
3021 pWrtShell->GotoTable("Table1");
3022 pWrtShell->SelTable();
3023 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
3024 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
3026 // This was 2 tables
3027 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
3028 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());
3030 // Undo results 2 tables
3031 rUndoManager.Undo();
3032 uno::Reference<container::XIndexAccess> xTables2(xTablesSupplier->getTextTables(),
3033 uno::UNO_QUERY);
3034 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables2->getCount());
3035 uno::Reference<text::XTextTable> xTable1b(xTableNames->getByName("Table1"), uno::UNO_QUERY);
3036 uno::Reference<text::XTextTable> xTable2b(xTableNames->getByName("Table2"), uno::UNO_QUERY);
3037 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
3038 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());
3040 // FIXME assert with Redo()
3043 void SwUiWriterTest4::testTdf147181_TrackedMovingOfMultipleTableRows()
3045 // Tracked moving of multiple table rows.
3046 // Source table (first one) has two rows;
3047 // destination (second one) has only one row
3048 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf115065.odt");
3049 CPPUNIT_ASSERT(pDoc);
3050 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3051 CPPUNIT_ASSERT(pWrtShell);
3053 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
3054 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
3055 uno::UNO_QUERY);
3056 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
3057 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
3058 CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
3059 CPPUNIT_ASSERT(xTableNames->hasByName("Table2"));
3060 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName("Table1"), uno::UNO_QUERY);
3061 uno::Reference<text::XTextTable> xTable2(xTableNames->getByName("Table2"), uno::UNO_QUERY);
3062 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
3063 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2->getRows()->getCount());
3065 // FIXME: doesn't work with empty rows, yet
3066 pWrtShell->Insert("x");
3067 pWrtShell->Down(false);
3068 pWrtShell->Insert("x");
3070 // enable redlining
3071 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
3072 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
3073 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
3075 // show changes
3076 CPPUNIT_ASSERT_MESSAGE(
3077 "redlines should be visible",
3078 IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
3080 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
3082 pWrtShell->GotoTable("Table2");
3083 SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
3084 // Destination point is the middle of the first cell of second table
3085 Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
3087 // Move rows of the first table into the second table
3088 pWrtShell->GotoTable("Table1");
3089 pWrtShell->SelTable();
3090 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
3091 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
3093 // still 2 tables, but the second one has got 3 rows
3094 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
3095 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
3096 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());
3098 // accept changes results 1 table (removing moved table)
3099 dispatchCommand(mxComponent, ".uno:AcceptAllTrackedChanges", {});
3100 Scheduler::ProcessEventsToIdle();
3101 uno::Reference<container::XIndexAccess> xTables2(xTablesSupplier->getTextTables(),
3102 uno::UNO_QUERY);
3103 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables2->getCount());
3104 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());
3106 // Undo results 2 tables
3107 rUndoManager.Undo();
3108 rUndoManager.Undo();
3109 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables2->getCount());
3110 uno::Reference<text::XTextTable> xTable1b(xTableNames->getByName("Table1"), uno::UNO_QUERY);
3111 uno::Reference<text::XTextTable> xTable2b(xTableNames->getByName("Table2"), uno::UNO_QUERY);
3112 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
3113 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());
3115 // reject changes results 2 table again, with the original row counts
3116 dispatchCommand(mxComponent, ".uno:RejectAllTrackedChanges", {});
3117 uno::Reference<container::XIndexAccess> xTables3(xTablesSupplier->getTextTables(),
3118 uno::UNO_QUERY);
3119 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables3->getCount());
3120 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
3121 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());
3124 void SwUiWriterTest4::testTdf115132()
3126 SwDoc* pDoc = createSwDoc();
3127 CPPUNIT_ASSERT(pDoc);
3128 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3129 CPPUNIT_ASSERT(pWrtShell);
3131 std::vector<OUString> vTestTableNames;
3133 // Create an empty paragraph that will separate first table from the rest
3134 pWrtShell->SplitNode();
3135 pWrtShell->StartOfSection();
3136 // Create a table at the start of document body
3137 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
3138 const SwTable* pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
3139 const SwTableFormat* pFormat = pTable->GetFrameFormat();
3140 CPPUNIT_ASSERT(pFormat);
3141 vTestTableNames.push_back(pFormat->GetName());
3142 pWrtShell->EndOfSection();
3143 // Create a table after a paragraph
3144 pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
3145 pFormat = pTable->GetFrameFormat();
3146 CPPUNIT_ASSERT(pFormat);
3147 vTestTableNames.push_back(pFormat->GetName());
3148 // Create a table immediately after the previous
3149 pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
3150 pFormat = pTable->GetFrameFormat();
3151 CPPUNIT_ASSERT(pFormat);
3152 vTestTableNames.push_back(pFormat->GetName());
3153 // Create a nested table in the middle of last row
3154 pWrtShell->GotoTable(vTestTableNames.back());
3155 for (int i = 0; i < 4; ++i)
3156 pWrtShell->GoNextCell(false);
3157 pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
3158 pFormat = pTable->GetFrameFormat();
3159 CPPUNIT_ASSERT(pFormat);
3160 vTestTableNames.push_back(pFormat->GetName());
3162 // Now check that in any cell in all tables we don't go out of a cell
3163 // using Delete or Backspace. We test cases when a table is the first node;
3164 // when we are in a first/middle/last cell in a row; when there's a paragraph
3165 // before/after this cell; when there's another table before/after this cell;
3166 // in nested table.
3167 for (const auto& rTableName : vTestTableNames)
3169 pWrtShell->GotoTable(rTableName);
3172 const SwStartNode* pNd = pWrtShell->GetCursor()->GetNode().FindTableBoxStartNode();
3173 pWrtShell->DelRight();
3174 CPPUNIT_ASSERT_EQUAL(pNd, pWrtShell->GetCursor()->GetNode().FindTableBoxStartNode());
3175 pWrtShell->DelLeft();
3176 CPPUNIT_ASSERT_EQUAL(pNd, pWrtShell->GetCursor()->GetNode().FindTableBoxStartNode());
3177 } while (pWrtShell->GoNextCell(false));
3181 void SwUiWriterTest4::testXDrawPagesSupplier()
3183 createSwDoc();
3184 uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
3185 CPPUNIT_ASSERT_MESSAGE("XDrawPagesSupplier interface is unavailable", xDrawPagesSupplier.is());
3186 uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
3187 CPPUNIT_ASSERT(xDrawPages.is());
3188 CPPUNIT_ASSERT_EQUAL_MESSAGE("There must be only a single DrawPage in Writer documents",
3189 sal_Int32(1), xDrawPages->getCount());
3190 uno::Any aDrawPage = xDrawPages->getByIndex(0);
3191 uno::Reference<drawing::XDrawPage> xDrawPageFromXDrawPages(aDrawPage, uno::UNO_QUERY);
3192 CPPUNIT_ASSERT(xDrawPageFromXDrawPages.is());
3194 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
3195 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
3196 CPPUNIT_ASSERT_EQUAL_MESSAGE(
3197 "The DrawPage accessed using XDrawPages must be the same as using XDrawPageSupplier",
3198 xDrawPage.get(), xDrawPageFromXDrawPages.get());
3201 void SwUiWriterTest4::testTdf116403()
3203 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf116403-considerborders.odt");
3204 // Check that before ToX update, the tab stop position is the old one
3205 uno::Reference<text::XTextRange> xParagraph = getParagraph(2, "1\t1");
3206 auto aTabs = getProperty<uno::Sequence<style::TabStop>>(xParagraph, "ParaTabStops");
3207 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aTabs.getLength());
3208 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(17000), aTabs[0].Position);
3210 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3211 const SwTOXBase* pTOX = pWrtShell->GetTOX(0);
3212 CPPUNIT_ASSERT(pTOX);
3213 pWrtShell->UpdateTableOf(*pTOX);
3215 xParagraph = getParagraph(2, "1\t1");
3216 aTabs = getProperty<uno::Sequence<style::TabStop>>(xParagraph, "ParaTabStops");
3217 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aTabs.getLength());
3218 // This was still 17000, refreshing ToX didn't take borders spacings and widths into account
3219 CPPUNIT_ASSERT_EQUAL_MESSAGE("Page borders must be considered for right-aligned tabstop",
3220 static_cast<sal_Int32>(17000 - 2 * 500 - 2 * 1),
3221 aTabs[0].Position);
3224 void SwUiWriterTest4::testHtmlCopyImages()
3226 // Load a document with an image.
3227 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "image.odt");
3229 // Trigger the copy part of HTML copy&paste.
3230 WriterRef xWrt = new SwHTMLWriter(/*rBaseURL=*/OUString());
3231 CPPUNIT_ASSERT(xWrt.is());
3233 xWrt->m_bWriteClipboardDoc = true;
3234 xWrt->m_bWriteOnlyFirstTable = false;
3235 xWrt->SetShowProgress(false);
3237 SvFileStream aStream(maTempFile.GetURL(), StreamMode::WRITE | StreamMode::TRUNC);
3238 SwWriter aWrt(aStream, *pDoc);
3239 aWrt.Write(xWrt);
3241 htmlDocUniquePtr pHtmlDoc = parseHtml(maTempFile);
3242 CPPUNIT_ASSERT(pHtmlDoc);
3244 // This failed, image was lost during HTML copy.
3245 OUString aImage = getXPath(pHtmlDoc, "/html/body/p/img", "src");
3246 // Also make sure that the image is not embedded (e.g. Word doesn't handle
3247 // embedded images).
3248 CPPUNIT_ASSERT(aImage.startsWith("file:///"));
3251 void SwUiWriterTest4::testTdf116789()
3253 createSwDoc(DATA_DIRECTORY, "tdf116789.fodt");
3254 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
3255 uno::Reference<text::XText> xText1;
3256 uno::Reference<text::XText> xText2;
3258 uno::Reference<text::XTextContent> xBookmark(
3259 xBookmarksSupplier->getBookmarks()->getByName("Bookmark 1"), uno::UNO_QUERY);
3260 xText1 = xBookmark->getAnchor()->getText();
3263 uno::Reference<text::XTextContent> xBookmark(
3264 xBookmarksSupplier->getBookmarks()->getByName("Bookmark 1"), uno::UNO_QUERY);
3265 xText2 = xBookmark->getAnchor()->getText();
3267 // This failed, we got two different SwXCell for the same bookmark anchor text.
3268 CPPUNIT_ASSERT_EQUAL(xText1, xText2);
3271 void SwUiWriterTest4::testTdf91801()
3273 // Tests calculation with several user field variables without prior user fields
3274 createSwDoc(DATA_DIRECTORY, "tdf91801.fodt");
3275 uno::Reference<text::XTextTable> xTable(getParagraphOrTable(1), uno::UNO_QUERY);
3276 uno::Reference<table::XCell> xCell(xTable->getCellByName("A1"));
3277 CPPUNIT_ASSERT_EQUAL(555.0, xCell->getValue());
3280 void SwUiWriterTest4::testTdf51223()
3282 SwDoc* pDoc = createSwDoc();
3283 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3284 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
3285 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3286 pWrtShell->Insert("i");
3287 pWrtShell->SplitNode(true);
3288 CPPUNIT_ASSERT_EQUAL(OUString("I"),
3289 static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3290 rUndoManager.Undo();
3291 CPPUNIT_ASSERT_EQUAL(OUString("i"),
3292 static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3295 void SwUiWriterTest4::testFontEmbedding()
3297 #if HAVE_MORE_FONTS && !defined(MACOSX)
3298 createSwDoc(DATA_DIRECTORY, "testFontEmbedding.odt");
3300 OString aContentBaseXpath("/office:document-content/office:font-face-decls");
3301 OString aSettingsBaseXpath("/office:document-settings/office:settings/config:config-item-set");
3303 xmlDocUniquePtr pXmlDoc;
3304 uno::Sequence<beans::PropertyValue> aDescriptor;
3305 utl::TempFile aTempFile;
3306 aTempFile.EnableKillingFile();
3308 // Get document settings
3309 uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY_THROW);
3310 uno::Reference<beans::XPropertySet> xProps(
3311 xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY_THROW);
3313 // Check font embedding state
3314 CPPUNIT_ASSERT_EQUAL(false, xProps->getPropertyValue("EmbedFonts").get<bool>());
3315 CPPUNIT_ASSERT_EQUAL(false, xProps->getPropertyValue("EmbedOnlyUsedFonts").get<bool>());
3316 // Font scripts should be enabled by default, however this has no effect unless "EmbedOnlyUsedFonts" is enabled
3317 CPPUNIT_ASSERT_EQUAL(true, xProps->getPropertyValue("EmbedLatinScriptFonts").get<bool>());
3318 CPPUNIT_ASSERT_EQUAL(true, xProps->getPropertyValue("EmbedAsianScriptFonts").get<bool>());
3319 CPPUNIT_ASSERT_EQUAL(true, xProps->getPropertyValue("EmbedComplexScriptFonts").get<bool>());
3321 // CASE 1 - no font embedding enabled
3323 // Save the document
3324 uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
3325 xStorable->storeToURL(aTempFile.GetURL(), aDescriptor);
3326 CPPUNIT_ASSERT(aTempFile.IsValid());
3328 // Check setting - No font embedding should be enabled
3329 pXmlDoc = parseExportInternal(aTempFile.GetURL(), "settings.xml");
3330 CPPUNIT_ASSERT(pXmlDoc);
3331 assertXPathContent(
3332 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedFonts']", "false");
3334 // Check content - No font-face-src nodes should be present
3335 pXmlDoc = parseExportInternal(aTempFile.GetURL(), "content.xml");
3336 CPPUNIT_ASSERT(pXmlDoc);
3338 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6);
3339 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']");
3340 assertXPath(
3341 pXmlDoc,
3342 aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 0);
3343 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']");
3344 assertXPath(pXmlDoc,
3345 aContentBaseXpath
3346 + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src",
3348 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']");
3349 assertXPath(pXmlDoc,
3350 aContentBaseXpath
3351 + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src",
3353 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']");
3354 assertXPath(pXmlDoc,
3355 aContentBaseXpath
3356 + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src",
3358 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']");
3359 assertXPath(pXmlDoc,
3360 aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 0);
3361 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']");
3362 assertXPath(pXmlDoc,
3363 aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 0);
3365 // CASE 2 - font embedding enabled, but embed used fonts disabled
3367 // Enable font embedding, disable embedding used font only
3368 xProps->setPropertyValue("EmbedFonts", uno::makeAny(true));
3369 xProps->setPropertyValue("EmbedOnlyUsedFonts", uno::makeAny(false));
3371 // Save the document again
3372 xStorable->storeToURL(aTempFile.GetURL(), aDescriptor);
3373 CPPUNIT_ASSERT(aTempFile.IsValid());
3375 // Check setting - font embedding should be enabled + embed only used fonts and scripts
3376 pXmlDoc = parseExportInternal(aTempFile.GetURL(), "settings.xml");
3377 CPPUNIT_ASSERT(pXmlDoc);
3378 assertXPathContent(
3379 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedFonts']", "true");
3380 assertXPathContent(
3381 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedOnlyUsedFonts']",
3382 "false");
3383 assertXPathContent(
3384 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedLatinScriptFonts']",
3385 "true");
3386 assertXPathContent(
3387 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedAsianScriptFonts']",
3388 "true");
3389 assertXPathContent(
3390 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedComplexScriptFonts']",
3391 "true");
3393 // Check content - font-face-src should be present only for "Liberation Sans" fonts
3395 pXmlDoc = parseExportInternal(aTempFile.GetURL(), "content.xml");
3396 CPPUNIT_ASSERT(pXmlDoc);
3398 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6);
3399 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']");
3400 assertXPath(
3401 pXmlDoc,
3402 aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 1);
3403 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']");
3404 assertXPath(pXmlDoc,
3405 aContentBaseXpath
3406 + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src",
3408 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']");
3409 assertXPath(pXmlDoc,
3410 aContentBaseXpath
3411 + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src",
3413 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']");
3414 assertXPath(pXmlDoc,
3415 aContentBaseXpath
3416 + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src",
3418 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']");
3419 assertXPath(pXmlDoc,
3420 aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 1);
3421 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']");
3422 assertXPath(pXmlDoc,
3423 aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 1);
3425 // CASE 3 - font embedding enabled, embed only used fonts enabled
3427 // Enable font embedding and setting to embed used fonts only
3428 xProps->setPropertyValue("EmbedFonts", uno::makeAny(true));
3429 xProps->setPropertyValue("EmbedOnlyUsedFonts", uno::makeAny(true));
3430 xProps->setPropertyValue("EmbedLatinScriptFonts", uno::makeAny(true));
3431 xProps->setPropertyValue("EmbedAsianScriptFonts", uno::makeAny(true));
3432 xProps->setPropertyValue("EmbedComplexScriptFonts", uno::makeAny(true));
3434 // Save the document again
3435 xStorable->storeToURL(aTempFile.GetURL(), aDescriptor);
3436 CPPUNIT_ASSERT(aTempFile.IsValid());
3438 // Check setting - font embedding should be enabled + embed only used fonts and scripts
3439 pXmlDoc = parseExportInternal(aTempFile.GetURL(), "settings.xml");
3440 CPPUNIT_ASSERT(pXmlDoc);
3441 assertXPathContent(
3442 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedFonts']", "true");
3443 assertXPathContent(
3444 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedOnlyUsedFonts']",
3445 "true");
3446 assertXPathContent(
3447 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedLatinScriptFonts']",
3448 "true");
3449 assertXPathContent(
3450 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedAsianScriptFonts']",
3451 "true");
3452 assertXPathContent(
3453 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedComplexScriptFonts']",
3454 "true");
3456 // Check content - font-face-src should be present only for "Liberation Sans" fonts
3458 pXmlDoc = parseExportInternal(aTempFile.GetURL(), "content.xml");
3459 CPPUNIT_ASSERT(pXmlDoc);
3461 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6);
3462 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']");
3463 assertXPath(
3464 pXmlDoc,
3465 aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 0);
3466 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']");
3467 assertXPath(pXmlDoc,
3468 aContentBaseXpath
3469 + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src",
3471 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']");
3472 assertXPath(pXmlDoc,
3473 aContentBaseXpath
3474 + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src",
3476 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']");
3477 assertXPath(pXmlDoc,
3478 aContentBaseXpath
3479 + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src",
3481 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']");
3482 assertXPath(pXmlDoc,
3483 aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 1);
3484 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']");
3485 assertXPath(pXmlDoc,
3486 aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 0);
3487 #endif
3490 // Unit test for fix inconsistent bookmark behavior around at-char/as-char anchored frames
3492 // We have a placeholder character in the sw doc model for as-char anchored frames,
3493 // so it's possible to have a bookmark before/after the frame or a non-collapsed bookmark
3494 // which covers the frame. The same is not true for at-char anchored frames,
3495 // where the anchor points to a doc model position, but there is no placeholder character.
3496 // If a bookmark is created covering the start and end of the anchor of the frame,
3497 // internally we create a collapsed bookmark which has the same position as the anchor of the frame.
3498 // When this doc model is handled by SwXParagraph::createEnumeration(),
3499 // first the frame and then the bookmark is appended to the text portion enumeration,
3500 // so your bookmark around the frame is turned into a collapsed bookmark after the frame.
3501 // (The same happens when we roundtrip an ODT document representing this doc model.)
3503 // Fix the problem by inserting collapsed bookmarks with affected anchor positions
3504 // (same position is the anchor for an at-char frame) into the enumeration in two stages:
3505 // first the start of them before frames and then the end of them + other bookmarks.
3506 // This way UNO API users get their non-collapsed bookmarks around at-char anchored frames,
3507 // similar to as-char ones.
3508 void SwUiWriterTest4::testInconsistentBookmark()
3510 // create test document with text and bookmark
3512 SwDoc* pDoc(createSwDoc(DATA_DIRECTORY, "testInconsistentBookmark.ott"));
3513 IDocumentMarkAccess& rIDMA(*pDoc->getIDocumentMarkAccess());
3514 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
3515 SwCursor aPaM(SwPosition(aIdx), nullptr);
3516 aPaM.SetMark();
3517 aPaM.MovePara(GoCurrPara, fnParaStart);
3518 aPaM.MovePara(GoCurrPara, fnParaEnd);
3519 rIDMA.makeMark(aPaM, "Mark", IDocumentMarkAccess::MarkType::BOOKMARK,
3520 ::sw::mark::InsertMode::New);
3521 aPaM.Exchange();
3522 aPaM.DeleteMark();
3525 // save document and verify the bookmark scoup
3527 // save document
3528 utl::TempFile aTempFile;
3529 save("writer8", aTempFile);
3531 // load only content.xml
3532 if (xmlDocUniquePtr pXmlDoc = parseExportInternal(aTempFile.GetURL(), "content.xml"))
3534 const OString aPath("/office:document-content/office:body/office:text/text:p");
3536 const int pos1 = getXPathPosition(pXmlDoc, aPath, "bookmark-start");
3537 const int pos2 = getXPathPosition(pXmlDoc, aPath, "control");
3538 const int pos3 = getXPathPosition(pXmlDoc, aPath, "bookmark-end");
3540 CPPUNIT_ASSERT_GREATER(pos1, pos2);
3541 CPPUNIT_ASSERT_GREATER(pos2, pos3);
3546 void SwUiWriterTest4::testSpellOnlineParameter()
3548 SwDoc* pDoc = createSwDoc();
3549 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3550 const SwViewOption* pOpt = pWrtShell->GetViewOptions();
3551 bool bSet = pOpt->IsOnlineSpell();
3553 uno::Sequence<beans::PropertyValue> params
3554 = comphelper::InitPropertySequence({ { "Enable", uno::makeAny(!bSet) } });
3555 dispatchCommand(mxComponent, ".uno:SpellOnline", params);
3556 CPPUNIT_ASSERT_EQUAL(!bSet, pOpt->IsOnlineSpell());
3558 // set the same state as now and we don't expect any change (no-toggle)
3559 params = comphelper::InitPropertySequence({ { "Enable", uno::makeAny(!bSet) } });
3560 dispatchCommand(mxComponent, ".uno:SpellOnline", params);
3561 CPPUNIT_ASSERT_EQUAL(!bSet, pOpt->IsOnlineSpell());
3564 void SwUiWriterTest4::testRedlineAutoCorrect()
3566 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "redline-autocorrect.fodt");
3568 dispatchCommand(mxComponent, ".uno:GoToEndOfDoc", {});
3570 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3572 // show tracked deletion with enabled change tracking
3573 RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
3574 CPPUNIT_ASSERT(nMode & (RedlineFlags::ShowDelete | RedlineFlags::ShowInsert));
3575 pWrtShell->SetRedlineFlags(nMode);
3576 CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);
3578 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
3579 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
3581 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3582 pWrtShell->AutoCorrect(corr, ' ');
3583 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3585 // tdf#83419 This was "Ts " removing the deletion of "t" silently by sentence capitalization
3586 OUString sReplaced("ts ");
3587 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3589 // hide delete redlines
3590 pWrtShell->SetRedlineFlags(nMode & ~RedlineFlags::ShowDelete);
3592 // repeat it with not visible redlining
3593 dispatchCommand(mxComponent, ".uno:Undo", {});
3595 pWrtShell->AutoCorrect(corr, ' ');
3596 nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3598 sReplaced = "S ";
3599 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3601 // show delete redlines
3602 pWrtShell->SetRedlineFlags(nMode);
3603 nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3605 // This still keep the tracked deletion, capitalize only the visible text "s"
3606 // with tracked deletion of the original character
3607 sReplaced = "tsS ";
3608 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3610 // repeat it with visible redlining and word auto replacement of "tset"
3611 dispatchCommand(mxComponent, ".uno:Undo", {});
3612 dispatchCommand(mxComponent, ".uno:Undo", {});
3614 pWrtShell->Insert("et");
3615 pWrtShell->AutoCorrect(corr, ' ');
3616 // This was "Ttest" removing the tracked deletion silently.
3617 // Don't replace, if a redline starts or ends within the text.
3618 sReplaced = "tset ";
3619 nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3620 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3622 // Otherwise replace it
3623 pWrtShell->Insert("tset");
3624 pWrtShell->AutoCorrect(corr, ' ');
3625 sReplaced = "tset test ";
3626 nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3627 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3629 // Including capitalization
3630 pWrtShell->Insert("end. word");
3631 pWrtShell->AutoCorrect(corr, ' ');
3632 sReplaced = "tset test end. Word ";
3633 nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3634 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3636 // tracked deletions after the correction point doesn't affect autocorrect
3637 dispatchCommand(mxComponent, ".uno:GoToStartOfDoc", {});
3638 pWrtShell->Insert("a");
3639 pWrtShell->AutoCorrect(corr, ' ');
3640 sReplaced = "A tset test end. Word ";
3641 nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3642 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3645 void SwUiWriterTest4::testRedlineAutoCorrect2()
3647 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "redline-autocorrect2.fodt");
3648 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3650 dispatchCommand(mxComponent, ".uno:GoToEndOfDoc", {});
3652 // show tracked deletion
3653 RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
3654 CPPUNIT_ASSERT(nMode & (RedlineFlags::ShowDelete | RedlineFlags::ShowInsert));
3655 pWrtShell->SetRedlineFlags(nMode);
3656 CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);
3658 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3659 pWrtShell->Insert("...");
3660 pWrtShell->AutoCorrect(corr, ' ');
3661 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3663 // This was "LoremLorem,โ€ฆ," (duplicating the deleted comma, but without deletion)
3664 // Don't replace, if a redline starts or ends within the text.
3665 OUString sReplaced = "Lorem,... ";
3666 nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3667 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3669 // Continue it:
3670 pWrtShell->Insert("Lorem,...");
3671 pWrtShell->AutoCorrect(corr, ' ');
3672 nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3673 sReplaced = u"Lorem,... Lorem,โ€ฆ ";
3674 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3677 void SwUiWriterTest4::testEmojiAutoCorrect()
3679 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "redline-autocorrect2.fodt");
3680 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3682 // Emoji replacement (:snowman: -> โ˜ƒ)
3684 // without change tracking
3685 CPPUNIT_ASSERT(!(pWrtShell->GetRedlineFlags() & RedlineFlags::On));
3686 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3687 pWrtShell->Insert(":snowman");
3688 pWrtShell->AutoCorrect(corr, ':');
3689 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3690 OUString sReplaced = u"โ˜ƒLorem,";
3691 nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3692 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3694 // with change tracking (showing redlines)
3695 RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
3696 CPPUNIT_ASSERT(nMode & (RedlineFlags::ShowDelete | RedlineFlags::ShowInsert));
3697 pWrtShell->SetRedlineFlags(nMode);
3698 CPPUNIT_ASSERT(nMode & RedlineFlags::On);
3699 CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);
3701 pWrtShell->Insert(":snowman");
3702 pWrtShell->AutoCorrect(corr, ':');
3703 sReplaced = u"โ˜ƒโ˜ƒLorem,";
3704 nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3706 // tdf#140674 This was ":snowman:" instead of autocorrect
3707 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3710 void SwUiWriterTest4::testTdf108423()
3712 SwDoc* pDoc = createSwDoc();
3713 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3714 // testing autocorrect of i' -> I' on start of first paragraph
3715 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3716 pWrtShell->Insert("i");
3717 const sal_Unicode cChar = '\'';
3718 pWrtShell->AutoCorrect(corr, cChar);
3719 // The word "i" should be capitalized due to autocorrect, followed by a typographical apostrophe
3720 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3721 OUString sIApostrophe(u"I\u2019");
3722 CPPUNIT_ASSERT_EQUAL(sIApostrophe,
3723 static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3724 pWrtShell->Insert(" i");
3725 pWrtShell->AutoCorrect(corr, cChar);
3726 OUString sText(sIApostrophe + u" " + sIApostrophe);
3727 CPPUNIT_ASSERT_EQUAL(sText, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3730 void SwUiWriterTest4::testTdf106164()
3732 SwDoc* pDoc = createSwDoc();
3733 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3734 // testing autocorrect of we're -> We're on start of first paragraph
3735 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3736 pWrtShell->Insert(u"we\u2019re");
3737 const sal_Unicode cChar = ' ';
3738 pWrtShell->AutoCorrect(corr, cChar);
3739 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3740 CPPUNIT_ASSERT_EQUAL(OUString(u"We\u2019re "),
3741 static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3744 void SwUiWriterTest4::testTdf54409()
3746 SwDoc* pDoc = createSwDoc();
3747 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3748 // testing autocorrect of "tset -> "test with typographical double quotation mark U+201C
3749 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3750 pWrtShell->Insert(u"\u201Ctset");
3751 const sal_Unicode cChar = ' ';
3752 pWrtShell->AutoCorrect(corr, cChar);
3753 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3754 OUString sReplaced(u"\u201Ctest ");
3755 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3756 // testing autocorrect of test" -> test" with typographical double quotation mark U+201D
3757 pWrtShell->Insert(u"and tset\u201D");
3758 pWrtShell->AutoCorrect(corr, cChar);
3759 OUString sReplaced2(sReplaced + u"and test\u201D ");
3760 CPPUNIT_ASSERT_EQUAL(sReplaced2, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3761 // testing autocorrect of "tset" -> "test" with typographical double quotation mark U+201C and U+201D
3762 pWrtShell->Insert(u"\u201Ctset\u201D");
3763 pWrtShell->AutoCorrect(corr, cChar);
3764 OUString sReplaced3(sReplaced2 + u"\u201Ctest\u201D ");
3765 CPPUNIT_ASSERT_EQUAL(sReplaced3, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3768 void SwUiWriterTest4::testTdf38394()
3770 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf38394.fodt");
3771 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3772 // testing autocorrect of French l'" -> l'ยซ (instead of l'ยป)
3773 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3774 pWrtShell->Insert(u"l\u2019");
3775 const sal_Unicode cChar = '"';
3776 pWrtShell->AutoCorrect(corr, cChar);
3777 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3778 OUString sReplaced(u"l\u2019ยซย ");
3779 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3780 // tdf#132301 autocorrect of qu'ยซ
3781 pWrtShell->Insert(u" qu\u2019");
3782 pWrtShell->AutoCorrect(corr, cChar);
3783 sReplaced += u" qu\u2019ยซย ";
3784 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3787 void SwUiWriterTest4::testTdf59666()
3789 SwDoc* pDoc = createSwDoc();
3790 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3791 // testing missing autocorrect of single Greek letters
3792 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3793 pWrtShell->Insert(u"\u03C0");
3794 const sal_Unicode cChar = ' ';
3795 pWrtShell->AutoCorrect(corr, cChar);
3796 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3797 CPPUNIT_ASSERT_EQUAL(OUString(u"\u03C0 "),
3798 static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3801 void SwUiWriterTest4::testTdf133524()
3803 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf133524.fodt");
3804 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3805 // 1. Testing autocorrect of >> and <<
3806 // Example: ยปwordยซ
3807 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3808 // >>
3809 pWrtShell->Insert(u">");
3810 pWrtShell->AutoCorrect(corr, '>');
3811 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3812 OUString sReplaced(u"ยป");
3813 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3814 // <<
3815 pWrtShell->Insert(u"word<");
3816 pWrtShell->AutoCorrect(corr, '<');
3817 sReplaced += u"wordยซ";
3818 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3819 // 2. Testing autocorrect of " to >> and << inside โ€ž...โ€
3820 // Example: โ€žSentence and ยปwordยซ.โ€
3821 // opening primary level quote
3822 pWrtShell->Insert(u" ");
3823 pWrtShell->AutoCorrect(corr, '"');
3824 sReplaced += u" โ€ž";
3825 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3826 // opening second level quote
3827 pWrtShell->Insert(u"Sentence and ");
3828 pWrtShell->AutoCorrect(corr, '"');
3829 sReplaced += u"Sentence and ยป";
3830 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3831 // closing second level quote
3832 pWrtShell->Insert(u"word");
3833 pWrtShell->AutoCorrect(corr, '"');
3834 sReplaced += u"wordยซ";
3835 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3836 // closing primary level quote
3837 pWrtShell->Insert(u".");
3838 pWrtShell->AutoCorrect(corr, '"');
3839 sReplaced += u".โ€";
3840 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3841 // tdf#134940 avoid premature replacement of "--" in "-->"
3842 pWrtShell->Insert(u" --");
3843 pWrtShell->AutoCorrect(corr, '>');
3844 OUString sReplaced2(sReplaced + u" -->");
3845 // This was "โ€“>" instead of "-->"
3846 CPPUNIT_ASSERT_EQUAL(sReplaced2, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3847 pWrtShell->AutoCorrect(corr, ' ');
3848 sReplaced += u" โ†’ ";
3849 // This was "โ€“>" instead of "โ†’"
3850 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3853 void SwUiWriterTest4::testTdf133524_Romanian()
3855 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf133524_ro.fodt");
3856 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3857 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3858 // 1. Testing autocorrect of " to << and >> inside โ€ž...โ€
3859 // Example: โ€žSentence and ยซwordยป.โ€
3860 // opening primary level quote
3861 pWrtShell->AutoCorrect(corr, '"');
3862 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3863 OUString sReplaced(u"โ€ž");
3864 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3865 // opening second level quote
3866 pWrtShell->Insert(u"Sentence and ");
3867 pWrtShell->AutoCorrect(corr, '"');
3868 sReplaced += u"Sentence and ยซ";
3869 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3870 // closing second level quote
3871 pWrtShell->Insert(u"word");
3872 pWrtShell->AutoCorrect(corr, '"');
3873 sReplaced += u"wordยป";
3874 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3875 // closing primary level quote
3876 pWrtShell->Insert(u".");
3877 pWrtShell->AutoCorrect(corr, '"');
3878 sReplaced += u".โ€";
3879 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3880 // 2. Testing recognition of closing double quotation mark โ€
3881 pWrtShell->Insert(u" ");
3882 pWrtShell->AutoCorrect(corr, '"');
3883 sReplaced += u" โ€ž";
3884 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3885 // 3. Testing recognition of alternative closing double quotation mark โ€œ
3886 pWrtShell->Insert(u"Alternative.โ€œ ");
3887 pWrtShell->AutoCorrect(corr, '"');
3888 sReplaced += u"Alternative.โ€œ โ€ž";
3889 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3892 void SwUiWriterTest4::testTdf128860()
3894 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf128860.fodt");
3895 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3896 // Second level ending quote: โ€šword' -> ,wordโ€˜
3897 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3898 pWrtShell->Insert(u"โ€šword");
3899 pWrtShell->AutoCorrect(corr, '\'');
3900 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3901 OUString sReplaced(u"โ€šwordโ€˜");
3902 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3903 // Us apostrophe without preceding starting quote: word' -> wordโ€™
3904 pWrtShell->Insert(u" word");
3905 pWrtShell->AutoCorrect(corr, '\'');
3906 sReplaced += u" wordโ€™";
3907 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3908 // But only after letters: word.' -> word.โ€˜
3909 pWrtShell->Insert(u" word.");
3910 pWrtShell->AutoCorrect(corr, '\'');
3911 sReplaced += u" word.โ€˜";
3912 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3915 void SwUiWriterTest4::testTdf123786()
3917 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf123786.fodt");
3918 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3919 // Second level ending quote: โ€žword' -> โ€žwordโ€œ
3920 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3921 pWrtShell->Insert(u"โ€žัะปะพะฒะพ");
3922 pWrtShell->AutoCorrect(corr, '\'');
3923 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3924 OUString sReplaced(u"โ€žัะปะพะฒะพโ€œ");
3925 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3926 // Us apostrophe without preceding starting quote: word' -> wordโ€™
3927 pWrtShell->Insert(u" ัะปะพะฒะพ");
3928 pWrtShell->AutoCorrect(corr, '\'');
3929 sReplaced += u" ัะปะพะฒะพโ€™";
3930 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3931 // But only after letters: word.' -> word.โ€œ
3932 pWrtShell->Insert(u" ัะปะพะฒะพ.");
3933 pWrtShell->AutoCorrect(corr, '\'');
3934 sReplaced += u" ัะปะพะฒะพ.โ€œ";
3935 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3938 void SwUiWriterTest4::testTdf133589()
3940 // Hungarian test document with right-to-left paragraph setting
3941 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf133589.fodt");
3942 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
3943 // translitere words to Old Hungarian
3944 SwAutoCorrect corr(*SvxAutoCorrCfg::Get().GetAutoCorrect());
3945 pWrtShell->Insert(u"szรฉkely");
3946 pWrtShell->AutoCorrect(corr, ' ');
3947 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetNode().GetIndex();
3948 OUString sReplaced(u"๐ณฅ๐ณ‹๐ณ“๐ณ‰๐ณ— ");
3949 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3950 // disambiguate consonants: asszony -> asz|szony
3951 pWrtShell->Insert(u"asszony");
3952 pWrtShell->AutoCorrect(corr, ' ');
3953 sReplaced += u"๐ณ€๐ณฅ๐ณฅ๐ณ›๐ณš ";
3954 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3955 // disambiguate consonants: kosszarv -> kos|szarv
3956 // (add explicit ZWSP temporarily for consonant disambiguation, because the requested
3957 // hu_HU hyphenation dictionary isn't installed on all testing platform)
3958 // pWrtShell->Insert(u"kosszarv");
3959 pWrtShell->Insert(u"kosโ€‹szarv");
3960 pWrtShell->AutoCorrect(corr, ' ');
3961 sReplaced += u"๐ณ“๐ณ›๐ณค๐ณฅ๐ณ€๐ณข๐ณฎ ";
3962 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3963 // transliterate numbers to Old Hungarian
3964 pWrtShell->Insert(u"2020");
3965 pWrtShell->AutoCorrect(corr, ' ');
3966 sReplaced += u"๐ณบ๐ณบ๐ณฟ๐ณผ๐ณผ ";
3967 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3969 // tdf#147546 transliterate punctuation marks
3971 // question mark
3972 pWrtShell->Insert(u"Kรฉrdล‘jel");
3973 pWrtShell->AutoCorrect(corr, '?');
3974 sReplaced += u"๐ฒ“๐ณ‹๐ณข๐ณ‡๐ณŸ๐ณ’๐ณ‰๐ณ–";
3975 OUString sReplaced2(sReplaced + "?");
3976 CPPUNIT_ASSERT_EQUAL(sReplaced2, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3977 pWrtShell->AutoCorrect(corr, ' ');
3978 sReplaced += u"โธฎ ";
3979 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3980 // comma
3981 pWrtShell->Insert(u"Vesszล‘");
3982 pWrtShell->AutoCorrect(corr, ',');
3983 sReplaced += u"๐ฒฎ๐ณ‰๐ณฅ๐ณฅ๐ณŸ";
3984 sReplaced2 = sReplaced + ",";
3985 CPPUNIT_ASSERT_EQUAL(sReplaced2, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3986 pWrtShell->AutoCorrect(corr, ' ');
3987 sReplaced += u"โน ";
3988 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3989 // semicolon
3990 pWrtShell->Insert(u"pontosvesszล‘");
3991 pWrtShell->AutoCorrect(corr, ';');
3992 sReplaced += u"๐ณ ๐ณ›๐ณ™๐ณฆ๐ณ›๐ณค๐ณฎ๐ณ‰๐ณฅ๐ณฅ๐ณŸ";
3993 sReplaced2 = sReplaced + ";";
3994 CPPUNIT_ASSERT_EQUAL(sReplaced2, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3995 pWrtShell->AutoCorrect(corr, ' ');
3996 sReplaced += u"โ ";
3997 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
3998 // quotation marks
3999 pWrtShell->Insert(u"โ€židรฉzล‘jelโ€");
4000 pWrtShell->AutoCorrect(corr, ' ');
4001 sReplaced += u"โน‚๐ณ๐ณ‡๐ณ‹๐ณฏ๐ณŸ๐ณ’๐ณ‰๐ณ–โ€Ÿ ";
4002 CPPUNIT_ASSERT_EQUAL(sReplaced, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
4005 void SwUiWriterTest4::testTdf143176()
4007 // Hungarian test document with right-to-left paragraph setting
4008 createSwDoc(DATA_DIRECTORY, "tdf143176.fodt");
4010 // transliterate the document to Old Hungarian (note: it only works
4011 // with right-to-left text direction and Default Paragraph Style)
4012 dispatchCommand(mxComponent, ".uno:AutoFormatApply", {});
4014 // This was the original "Lorem ipsum..."
4015 CPPUNIT_ASSERT_EQUAL(OUString(u"๐ฒ–๐ณ›๐ณข๐ณ‰๐ณ˜ ๐ณ๐ณ ๐ณค๐ณช๐ณ˜ ๐ณ‡๐ณ›๐ณ–๐ณ›๐ณข "
4016 u"๐ณค๐ณ๐ณฆ ๐ณ€๐ณ˜๐ณ‰๐ณฆโน"),
4017 getParagraph(1)->getString());
4018 CPPUNIT_ASSERT_EQUAL(OUString(u"๐ณ„๐ณ›๐ณ™๐ณค๐ณ‰๐ณ„๐ณฆ๐ณ‰๐ณฆ๐ณช๐ณข "
4019 u"๐ณ€๐ณ‡๐ณ๐ณ ๐ณ๐ณค๐ณ„๐ณ๐ณ™๐ณ ๐ณ‰๐ณ–๐ณ๐ณฆ."),
4020 getParagraph(2)->getString());
4023 void SwUiWriterTest4::testInsertLongDateFormat()
4025 // only for Hungarian, yet
4026 createSwDoc(DATA_DIRECTORY, "tdf133524.fodt");
4027 dispatchCommand(mxComponent, ".uno:InsertDateField", {});
4028 // Make sure that the document starts with a field now, and its expanded string value contains space
4029 const uno::Reference<text::XTextRange> xField = getRun(getParagraph(1), 1);
4030 CPPUNIT_ASSERT_EQUAL(OUString("TextField"), getProperty<OUString>(xField, "TextPortionType"));
4031 // the date format was "YYYY-MM-DD", but now "YYYY. MMM DD."
4032 CPPUNIT_ASSERT(xField->getString().indexOf(" ") > -1);
4035 void SwUiWriterTest4::testTdf129270()
4037 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf129270.odt");
4038 CPPUNIT_ASSERT(pDoc);
4039 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
4040 CPPUNIT_ASSERT(pWrtShell);
4041 SwXTextDocument* pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
4042 CPPUNIT_ASSERT(pXTextDocument);
4044 // Go to document end
4045 pWrtShell->SttEndDoc(/*bStt=*/false);
4047 // Press enter
4048 pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RETURN);
4049 Scheduler::ProcessEventsToIdle();
4051 // Numbering for previous outline should remain the same "2"
4052 CPPUNIT_ASSERT_EQUAL(OUString("2"), getProperty<OUString>(getParagraph(4), "ListLabelString"));
4054 // Numbering for newly created outline should be "2.1"
4055 CPPUNIT_ASSERT_EQUAL(OUString("2.1"),
4056 getProperty<OUString>(getParagraph(5), "ListLabelString"));
4059 void SwUiWriterTest4::testInsertPdf()
4061 auto pPdfium = vcl::pdf::PDFiumLibrary::get();
4062 if (!pPdfium)
4064 return;
4067 createSwDoc();
4069 // insert the PDF into the document
4070 uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
4071 { { "FileName",
4072 uno::Any(m_directories.getURLFromSrc(DATA_DIRECTORY) + "hello-world.pdf") } }));
4073 dispatchCommand(mxComponent, ".uno:InsertGraphic", aArgs);
4075 // Save and load cycle
4076 reload("writer8", "testInsertPdf.odt");
4078 uno::Reference<drawing::XShape> xShape = getShape(1);
4079 // Assert that we have a replacement graphics
4080 auto xReplacementGraphic
4081 = getProperty<uno::Reference<graphic::XGraphic>>(xShape, "ReplacementGraphic");
4082 CPPUNIT_ASSERT(xReplacementGraphic.is());
4084 auto xGraphic = getProperty<uno::Reference<graphic::XGraphic>>(xShape, "Graphic");
4085 CPPUNIT_ASSERT(xGraphic.is());
4086 // Assert that the graphic is a PDF
4087 CPPUNIT_ASSERT_EQUAL(OUString("application/pdf"), getProperty<OUString>(xGraphic, "MimeType"));
4090 void SwUiWriterTest4::testTdf143760WrapContourToOff()
4092 // Actually, this is an ooxmlexport test. It is here because here is a ready environment
4093 // to change a shape by dispatchCommand.
4094 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf143760_ContourToWrapOff.docx");
4095 CPPUNIT_ASSERT(pDoc);
4096 CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(getShape(1), "SurroundContour"));
4098 // Mark the object
4099 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
4100 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
4101 SdrObject* pObject = pPage->GetObj(0);
4102 CPPUNIT_ASSERT(pObject);
4103 SdrView* pView = pWrtShell->GetDrawView();
4104 pView->MarkObj(pObject, pView->GetSdrPageView());
4106 // Set "wrap off"
4107 dispatchCommand(mxComponent, ".uno:WrapOff", {});
4108 CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(getShape(1), "SurroundContour"));
4110 // Without fix this had failed, because the shape was written to file with contour.
4111 reload("Office Open XML Text", "tdf143760_ContourToWrapOff.docx");
4112 CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(getShape(1), "SurroundContour"));
4115 void SwUiWriterTest4::testHatchFill()
4117 createSwDoc();
4119 // Add a rectangle shape to the document.
4120 uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
4121 uno::Reference<drawing::XShape> xShape(
4122 xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
4123 xShape->setSize(awt::Size(10000, 10000));
4124 xShape->setPosition(awt::Point(1000, 1000));
4125 uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
4126 xShapeProps->setPropertyValue("FillStyle", uno::makeAny(drawing::FillStyle_HATCH));
4127 xShapeProps->setPropertyValue("FillHatchName", uno::makeAny(OUString("Black 0 Degrees")));
4128 xShapeProps->setPropertyValue("FillBackground", uno::makeAny(false));
4129 xShapeProps->setPropertyValue("FillTransparence", uno::makeAny(sal_Int32(30)));
4130 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
4131 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
4132 xDrawPage->add(xShape);
4134 // Save it as DOCX and load it again.
4135 reload("Office Open XML Text", "hatchFill.docx");
4136 CPPUNIT_ASSERT_EQUAL(1, getShapes());
4138 // tdf#127989 Without fix this had failed, because the background of the hatch was not set as 'no background'.
4139 CPPUNIT_ASSERT(!getProperty<bool>(getShape(1), "FillBackground"));
4141 // tdf#146822 Without fix this had failed, because the transparency value of the hatch was not exported.
4142 CPPUNIT_ASSERT_EQUAL(sal_Int32(30), getProperty<sal_Int32>(getShape(1), "FillTransparence"));
4145 void SwUiWriterTest4::testTdf62032ApplyStyle()
4147 SwDoc* pDoc = createSwDoc(DATA_DIRECTORY, "tdf62032_apply_style.odt");
4148 SwWrtShell* pWrtSh = pDoc->GetDocShell()->GetWrtShell();
4150 pWrtSh->Down(/*bSelect=*/false);
4152 uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({
4153 { "Style", uno::Any(OUString("A 2")) },
4154 { "FamilyName", uno::Any(OUString("ParagraphStyles")) },
4156 dispatchCommand(mxComponent, ".uno:StyleApply", aPropertyValues);
4158 // Without the fix in place, it fails with:
4159 // - Expected: 1.1
4160 // - Actual : 2
4161 CPPUNIT_ASSERT_EQUAL(OUString("1.1"),
4162 getProperty<OUString>(getParagraph(2), "ListLabelString").trim());
4165 CPPUNIT_TEST_SUITE_REGISTRATION(SwUiWriterTest4);
4166 CPPUNIT_PLUGIN_IMPLEMENT();
4168 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */