Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / qa / extras / uiwriter / uiwriter6.cxx
blob316181c37cff0ca159cd7db7d115563feb035722
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <com/sun/star/drawing/FillStyle.hpp>
11 #include <swmodeltestbase.hxx>
12 #include <cntfrm.hxx>
13 #include <itabenum.hxx>
14 #include <ndtxt.hxx>
15 #include <wrtsh.hxx>
16 #include <drawdoc.hxx>
17 #include <view.hxx>
18 #include <com/sun/star/text/XTextColumns.hpp>
20 #include <svx/svdpage.hxx>
21 #include <svx/svdview.hxx>
22 #include <svl/itemiter.hxx>
23 #include <vcl/filter/PDFiumLibrary.hxx>
25 #include <dbfld.hxx>
26 #include <txatbase.hxx>
27 #include <IDocumentDrawModelAccess.hxx>
28 #include <IDocumentRedlineAccess.hxx>
29 #include <IDocumentLayoutAccess.hxx>
30 #include <UndoManager.hxx>
31 #include <unotools/syslocaleoptions.hxx>
33 #include <svl/stritem.hxx>
34 #include <sfx2/viewfrm.hxx>
35 #include <sfx2/dispatch.hxx>
36 #include <cmdid.h>
37 #include <tools/json_writer.hxx>
38 #include <boost/property_tree/json_parser.hpp>
40 #include <com/sun/star/text/XTextTable.hpp>
41 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
42 #include <o3tl/cppunittraitshelper.hxx>
43 #include <swdtflvr.hxx>
44 #include <comphelper/propertysequence.hxx>
45 #include <comphelper/processfactory.hxx>
46 #include <comphelper/sequence.hxx>
47 #include <comphelper/scopeguard.hxx>
48 #include <editeng/swafopt.hxx>
49 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
50 #include <vcl/scheduler.hxx>
51 #include <config_fonts.h>
52 #include <test/htmltesttools.hxx>
53 #include <wrthtml.hxx>
54 #include <dbmgr.hxx>
55 #include <rootfrm.hxx>
56 #include <unotxdoc.hxx>
57 #include <wrong.hxx>
58 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
59 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
60 #include <com/sun/star/linguistic2/XSpellChecker1.hpp>
61 #include <linguistic/misc.hxx>
63 #include <workctrl.hxx>
65 using namespace osl;
66 using namespace com::sun::star;
67 using namespace com::sun::star::beans;
68 using namespace com::sun::star::lang;
69 using namespace com::sun::star::uno;
70 using namespace com::sun::star::linguistic2;
71 using namespace linguistic;
73 namespace
75 sal_Int32 lcl_getAttributeIDFromHints(const SwpHints& hints)
77 for (size_t i = 0; i < hints.Count(); ++i)
79 const SwTextAttr* hint = hints.Get(i);
80 if (hint->Which() == RES_TXTATR_AUTOFMT)
82 const SwFormatAutoFormat& rFmt = hint->GetAutoFormat();
83 SfxItemIter aIter(*rFmt.GetStyleHandle());
84 return aIter.GetCurItem()->Which();
87 return -1;
90 uno::Reference<XLinguServiceManager2> GetLngSvcMgr_Impl()
92 uno::Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
93 uno::Reference<XLinguServiceManager2> xRes = LinguServiceManager::create(xContext);
94 return xRes;
96 } //namespace
98 class SwUiWriterTest6 : public SwModelTestBase, public HtmlTestTools
100 public:
101 SwUiWriterTest6()
102 : SwModelTestBase("/sw/qa/extras/uiwriter/data/")
107 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf116640)
109 createSwDoc();
111 uno::Sequence<beans::PropertyValue> aArgs(
112 comphelper::InitPropertySequence({ { "Columns", uno::Any(sal_Int32(2)) } }));
114 dispatchCommand(mxComponent, ".uno:InsertSection", aArgs);
116 uno::Reference<text::XTextSectionsSupplier> xTextSectionsSupplier(mxComponent, uno::UNO_QUERY);
117 uno::Reference<container::XIndexAccess> xSections(xTextSectionsSupplier->getTextSections(),
118 uno::UNO_QUERY);
119 uno::Reference<beans::XPropertySet> xTextSection(xSections->getByIndex(0), uno::UNO_QUERY);
121 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
123 uno::Reference<text::XTextColumns> xTextColumns
124 = getProperty<uno::Reference<text::XTextColumns>>(xTextSection, "TextColumns");
125 CPPUNIT_ASSERT_EQUAL(sal_Int16(2), xTextColumns->getColumnCount());
127 dispatchCommand(mxComponent, ".uno:Undo", {});
129 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xSections->getCount());
131 dispatchCommand(mxComponent, ".uno:Redo", {});
133 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
135 dispatchCommand(mxComponent, ".uno:Undo", {});
137 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xSections->getCount());
140 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf108524)
142 createSwDoc("tdf108524.odt");
143 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
144 // In total we expect two cells containing a section.
145 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/section", 2);
147 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell/section", 1);
148 // This was 0, section wasn't split, instead it was only on the first page
149 // and it was cut off.
150 assertXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell/section", 1);
153 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testLinesInSectionInTable)
155 // This is similar to testTdf108524(), but the page boundary now is not in
156 // the middle of a multi-line paragraph: the section only contains oneliner
157 // paragraphs instead.
158 createSwDoc("lines-in-section-in-table.odt");
159 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
160 // In total we expect two cells containing a section.
161 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/section", 2);
163 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell/section", 1);
164 // This was 0, section wasn't split, instead it was only on the first page
165 // and it was cut off.
166 assertXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell/section", 1);
169 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testLinesMoveBackwardsInSectionInTable)
171 #if HAVE_MORE_FONTS
172 // Assert that paragraph "4" is on page 1 and "5" is on page 2.
173 createSwDoc("lines-in-section-in-table.odt");
174 SwDoc* pDoc = getSwDoc();
175 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
176 assertXPath(pXmlDoc, "/root/page", 2);
177 SwNodeOffset nPara4Node(
178 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/section/txt[last()]", "txtNodeIndex")
179 .toUInt32());
180 CPPUNIT_ASSERT_EQUAL(OUString("4"), pDoc->GetNodes()[nPara4Node]->GetTextNode()->GetText());
181 SwNodeOffset nPara5Node(
182 getXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell[1]/section/txt[1]", "txtNodeIndex")
183 .toUInt32());
184 CPPUNIT_ASSERT_EQUAL(OUString("5"), pDoc->GetNodes()[nPara5Node]->GetTextNode()->GetText());
186 // Remove paragraph "4".
187 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
188 while (pWrtShell->GetCursor()->GetPointNode().GetIndex() < nPara4Node)
189 pWrtShell->Down(/*bSelect=*/false);
190 pWrtShell->EndPara();
191 pWrtShell->Up(/*bSelect=*/true);
192 pWrtShell->DelLeft();
194 // Assert that paragraph "5" is now moved back to page 1 and is the last paragraph there.
195 discardDumpedLayout();
196 pXmlDoc = parseLayoutDump();
197 SwNodeOffset nPage1LastNode(
198 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/section/txt[last()]", "txtNodeIndex")
199 .toUInt32());
200 // This was "3", paragraph "4" was deleted, but "5" was not moved backwards from page 2.
201 CPPUNIT_ASSERT_EQUAL(OUString("5"), pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
202 #endif
205 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTableInSection)
207 #if HAVE_MORE_FONTS
208 // The document has a section, containing a table that spans over 2 pages.
209 createSwDoc("table-in-sect.odt");
210 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
211 // In total we expect 4 cells.
212 assertXPath(pXmlDoc, "/root/page/body/section/tab/row/cell", 4);
214 // Assert that on both pages the section contains 2 cells.
215 assertXPath(pXmlDoc, "/root/page[1]/body/section/tab/row/cell", 2);
216 assertXPath(pXmlDoc, "/root/page[2]/body/section/tab/row/cell", 2);
217 #endif
220 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTableInNestedSection)
222 #if HAVE_MORE_FONTS
223 // The document has a nested section, containing a table that spans over 2 pages.
224 // This crashed the layout.
225 createSwDoc("rhbz739252-3.odt");
226 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
227 // Make sure the table is inside a section and spans over 2 pages.
228 assertXPath(pXmlDoc, "//page[1]//section/tab", 1);
229 assertXPath(pXmlDoc, "//page[2]//section/tab", 1);
230 #endif
233 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112741)
235 #if HAVE_MORE_FONTS
236 createSwDoc("tdf112741.fodt");
237 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
238 // This was 5 pages.
239 assertXPath(pXmlDoc, "//page", 4);
240 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell/section", 1);
241 assertXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row/cell/section", 1);
242 // This failed, 3rd page contained no sections.
243 assertXPath(pXmlDoc, "//page[3]/body/tab/row/cell/tab/row/cell/section", 1);
244 assertXPath(pXmlDoc, "//page[4]/body/tab/row/cell/tab/row/cell/section", 1);
245 #endif
248 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112860)
250 #if HAVE_MORE_FONTS
251 // The document has a split section inside a nested table, and also a table
252 // in the footer.
253 // This crashed the layout.
254 createSwDoc("tdf112860.fodt");
255 #endif
258 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113287)
260 #if HAVE_MORE_FONTS
261 createSwDoc("tdf113287.fodt");
262 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
263 assertXPath(pXmlDoc, "//page", 2);
264 sal_uInt32 nCellTop
265 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell[1]/infos/bounds", "top").toUInt32();
266 sal_uInt32 nSectionTop
267 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell[1]/section/infos/bounds", "top")
268 .toUInt32();
269 // Make sure section frame is inside the cell frame.
270 // Expected greater than 4593, was only 3714.
271 CPPUNIT_ASSERT_GREATER(nCellTop, nSectionTop);
272 #endif
275 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113445)
277 #if HAVE_MORE_FONTS
278 // Force multiple-page view.
279 createSwDoc("tdf113445.fodt");
280 SwDoc* pDoc = getSwDoc();
281 SwDocShell* pDocShell = pDoc->GetDocShell();
282 SwView* pView = pDocShell->GetView();
283 pView->SetViewLayout(/*nColumns=*/2, /*bBookMode=*/false);
284 calcLayout();
286 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
287 assertXPath(pXmlDoc, "//page", 2);
288 sal_uInt32 nPage1Left = getXPath(pXmlDoc, "//page[1]/infos/bounds", "left").toUInt32();
289 sal_uInt32 nPage2Left = getXPath(pXmlDoc, "//page[2]/infos/bounds", "left").toUInt32();
290 // Make sure that page 2 is on the right hand side of page 1, not below it.
291 CPPUNIT_ASSERT_GREATER(nPage1Left, nPage2Left);
293 // Insert a new paragraph at the start of the document.
294 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
295 pWrtShell->StartOfSection();
296 pWrtShell->SplitNode();
297 discardDumpedLayout();
298 pXmlDoc = parseLayoutDump();
300 // Make sure that Table2:C5 and Table2:D5 has its section frame inside the cell frame.
301 sal_uInt32 nCell3Top
302 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[3]/infos/bounds", "top")
303 .toUInt32();
304 sal_uInt32 nSection3Top
305 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[3]/section/infos/bounds",
306 "top")
307 .toUInt32();
308 CPPUNIT_ASSERT_GREATER(nCell3Top, nSection3Top);
309 sal_uInt32 nCell4Top
310 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[4]/infos/bounds", "top")
311 .toUInt32();
312 sal_uInt32 nSection4Top
313 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[4]/section/infos/bounds",
314 "top")
315 .toUInt32();
316 CPPUNIT_ASSERT_GREATER(nCell4Top, nSection4Top);
317 // Also check if the two cells in the same row have the same top position.
318 // This was 4818, expected only 1672.
319 CPPUNIT_ASSERT_EQUAL(nCell3Top, nCell4Top);
320 #endif
323 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113686)
325 #if HAVE_MORE_FONTS
326 createSwDoc("tdf113686.fodt");
327 SwDoc* pDoc = getSwDoc();
328 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
329 assertXPath(pXmlDoc, "/root/page", 2);
330 SwNodeOffset nPage1LastNode(
331 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/tab/row/cell[1]/txt[last()]",
332 "txtNodeIndex")
333 .toUInt32());
334 CPPUNIT_ASSERT_EQUAL(OUString("Table2:A1-P10"),
335 pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
336 SwNodeOffset nPage2FirstNode(
337 getXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell[1]/section/txt[1]", "txtNodeIndex")
338 .toUInt32());
339 CPPUNIT_ASSERT_EQUAL(OUString("Table1:A1"),
340 pDoc->GetNodes()[nPage2FirstNode]->GetTextNode()->GetText());
342 // Remove page 2.
343 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
344 while (pWrtShell->GetCursor()->Start()->GetNodeIndex() < nPage1LastNode)
345 pWrtShell->Down(/*bSelect=*/false);
346 pWrtShell->EndPara();
347 for (int i = 0; i < 3; ++i)
348 pWrtShell->Up(/*bSelect=*/true);
349 pWrtShell->DelLeft();
351 // Assert that the second page is removed.
352 discardDumpedLayout();
353 pXmlDoc = parseLayoutDump();
354 // This was still 2, content from 2nd page was not moved.
355 assertXPath(pXmlDoc, "/root/page", 1);
356 #endif
359 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTableInSectionInTable)
361 #if HAVE_MORE_FONTS
362 // The document has a table, containing a section, containing a nested
363 // table.
364 // This crashed the layout.
365 createSwDoc("i95698.odt");
366 #endif
369 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable)
371 #if HAVE_MORE_FONTS
372 // The document has a nested table, containing a multi-line section at a
373 // page boundary.
374 // This crashed the layout later in SwFrame::IsFootnoteAllowed().
375 createSwDoc("tdf112109.fodt");
376 #endif
379 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable2)
381 #if HAVE_MORE_FONTS
382 createSwDoc("split-section-in-nested-table.fodt");
383 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
384 sal_uInt32 nSection1
385 = getXPath(pXmlDoc, "//page[1]//body/tab/row/cell/tab/row/cell/section", "id").toUInt32();
386 sal_uInt32 nSection1Follow
387 = getXPath(pXmlDoc, "//page[1]//body/tab/row/cell/tab/row/cell/section", "follow")
388 .toUInt32();
389 // This failed, the section wasn't split inside a nested table.
390 sal_uInt32 nSection2
391 = getXPath(pXmlDoc, "//page[2]//body/tab/row/cell/tab/row/cell/section", "id").toUInt32();
392 sal_uInt32 nSection2Precede
393 = getXPath(pXmlDoc, "//page[2]//body/tab/row/cell/tab/row/cell/section", "precede")
394 .toUInt32();
396 // Make sure that the first's follow and the second's precede is correct.
397 CPPUNIT_ASSERT_EQUAL(nSection2, nSection1Follow);
398 CPPUNIT_ASSERT_EQUAL(nSection1, nSection2Precede);
399 #endif
402 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable3)
404 #if HAVE_MORE_FONTS
405 createSwDoc("tdf113153.fodt");
407 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
408 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
409 uno::UNO_QUERY);
410 uno::Reference<container::XNamed> xTable(xTables->getByIndex(1), uno::UNO_QUERY);
411 CPPUNIT_ASSERT_EQUAL(OUString("Table16"), xTable->getName());
413 uno::Reference<text::XTextTable> xRowSupplier(xTable, uno::UNO_QUERY);
414 uno::Reference<table::XTableRows> xRows = xRowSupplier->getRows();
415 uno::Reference<beans::XPropertySet> xRow(xRows->getByIndex(1), uno::UNO_QUERY);
416 xRow->setPropertyValue("IsSplitAllowed", uno::Any(true));
417 // This never returned.
418 calcLayout();
420 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
421 sal_uInt32 nTable1 = getXPath(pXmlDoc, "//page[1]//body/tab", "id").toUInt32();
422 sal_uInt32 nTable1Follow = getXPath(pXmlDoc, "//page[1]//body/tab", "follow").toUInt32();
423 sal_uInt32 nTable2 = getXPath(pXmlDoc, "//page[2]//body/tab", "id").toUInt32();
424 sal_uInt32 nTable2Precede = getXPath(pXmlDoc, "//page[2]//body/tab", "precede").toUInt32();
425 sal_uInt32 nTable2Follow = getXPath(pXmlDoc, "//page[2]//body/tab", "follow").toUInt32();
426 sal_uInt32 nTable3 = getXPath(pXmlDoc, "//page[3]//body/tab", "id").toUInt32();
427 sal_uInt32 nTable3Precede = getXPath(pXmlDoc, "//page[3]//body/tab", "precede").toUInt32();
429 // Make sure the outer table frames are linked together properly.
430 CPPUNIT_ASSERT_EQUAL(nTable2, nTable1Follow);
431 CPPUNIT_ASSERT_EQUAL(nTable1, nTable2Precede);
432 CPPUNIT_ASSERT_EQUAL(nTable3, nTable2Follow);
433 CPPUNIT_ASSERT_EQUAL(nTable2, nTable3Precede);
434 #endif
437 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable4)
439 #if HAVE_MORE_FONTS
440 createSwDoc("tdf113520.fodt");
441 SwDoc* pDoc = getSwDoc();
442 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
443 assertXPath(pXmlDoc, "/root/page", 3);
444 SwNodeOffset nPage1LastNode(
445 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/tab/row/cell[1]/section/txt[last()]",
446 "txtNodeIndex")
447 .toUInt32());
448 CPPUNIT_ASSERT_EQUAL(OUString("Section1:P10"),
449 pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
450 SwNodeOffset nPage3FirstNode(
451 getXPath(pXmlDoc, "/root/page[3]/body/tab/row/cell[1]/tab/row/cell[1]/section/txt[1]",
452 "txtNodeIndex")
453 .toUInt32());
454 CPPUNIT_ASSERT_EQUAL(OUString("Section1:P23"),
455 pDoc->GetNodes()[nPage3FirstNode]->GetTextNode()->GetText());
457 // Remove page 2.
458 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
459 while (pWrtShell->GetCursor()->Start()->GetNodeIndex() < nPage1LastNode)
460 pWrtShell->Down(/*bSelect=*/false);
461 pWrtShell->EndPara();
462 while (pWrtShell->GetCursor()->End()->GetNodeIndex() < nPage3FirstNode)
463 pWrtShell->Down(/*bSelect=*/true);
464 pWrtShell->EndPara(/*bSelect=*/true);
465 pWrtShell->DelLeft();
467 // Assert that the page is removed.
468 discardDumpedLayout();
469 pXmlDoc = parseLayoutDump();
470 // This was 3, page 2 was emptied, but it wasn't removed.
471 assertXPath(pXmlDoc, "/root/page", 2);
473 // Make sure the outer table frames are linked together properly.
474 sal_uInt32 nTable1 = getXPath(pXmlDoc, "//page[1]//body/tab", "id").toUInt32();
475 sal_uInt32 nTable1Follow = getXPath(pXmlDoc, "//page[1]//body/tab", "follow").toUInt32();
476 sal_uInt32 nTable2 = getXPath(pXmlDoc, "//page[2]//body/tab", "id").toUInt32();
477 sal_uInt32 nTable2Precede = getXPath(pXmlDoc, "//page[2]//body/tab", "precede").toUInt32();
478 CPPUNIT_ASSERT_EQUAL(nTable2, nTable1Follow);
479 CPPUNIT_ASSERT_EQUAL(nTable1, nTable2Precede);
480 #endif
483 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112160)
485 #if HAVE_MORE_FONTS
486 // Assert that the A2 cell is on page 1.
487 createSwDoc("tdf112160.fodt");
488 SwDoc* pDoc = getSwDoc();
489 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
490 SwNodeOffset nA2CellNode(getXPath(pXmlDoc,
491 "/root/page[1]/body/tab/row[2]/cell[1]/section/txt[last()]",
492 "txtNodeIndex")
493 .toUInt32());
494 CPPUNIT_ASSERT_EQUAL(OUString("Table1.A2"),
495 pDoc->GetNodes()[nA2CellNode]->GetTextNode()->GetText());
497 // Append a new paragraph to the end of the A2 cell.
498 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
499 while (pWrtShell->GetCursor()->GetPointNode().GetIndex() < nA2CellNode)
500 pWrtShell->Down(/*bSelect=*/false);
501 pWrtShell->EndPara();
502 pWrtShell->SplitNode();
504 // Assert that after A2 got extended, D2 stays on page 1.
505 discardDumpedLayout();
506 pXmlDoc = parseLayoutDump();
507 sal_uInt32 nD2CellNode
508 = getXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[last()]/section/txt[last()]",
509 "txtNodeIndex")
510 .toUInt32();
511 // This was Table1.C2, Table1.D2 was moved to the next page, unexpected.
512 CPPUNIT_ASSERT_EQUAL(OUString("Table1.D2"),
513 pDoc->GetNodes()[SwNodeOffset(nD2CellNode)]->GetTextNode()->GetText());
514 #endif
517 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf114536)
519 // This crashed in SwTextFormatter::MergeCharacterBorder() due to a
520 // use after free.
521 createSwDoc("tdf114536.odt");
524 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testParagraphOfTextRange)
526 createSwDoc("paragraph-of-text-range.odt");
527 SwDoc* pDoc = getSwDoc();
529 // Enter the table.
530 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
531 pWrtShell->Down(/*bSelect=*/false);
532 CPPUNIT_ASSERT(pWrtShell->IsCursorInTable());
533 // Enter the section.
534 pWrtShell->Down(/*bSelect=*/false);
535 CPPUNIT_ASSERT(pWrtShell->IsDirectlyInSection());
537 // Assert that we get the right paragraph object.
538 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
539 uno::Reference<text::XTextViewCursorSupplier> xController(xModel->getCurrentController(),
540 uno::UNO_QUERY);
541 uno::Reference<text::XTextRange> xViewCursor = xController->getViewCursor();
542 // This failed as there were no TextParagraph property.
543 auto xParagraph
544 = getProperty<uno::Reference<text::XTextRange>>(xViewCursor->getStart(), "TextParagraph");
545 CPPUNIT_ASSERT_EQUAL(OUString("In section"), xParagraph->getString());
548 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf99689TableOfContents)
550 createSwDoc("tdf99689.odt");
551 SwDoc* pDoc = getSwDoc();
552 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
553 pWrtShell->GotoNextTOXBase();
554 const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
555 pWrtShell->UpdateTableOf(*pTOXBase);
556 SwCursorShell* pShell(pDoc->GetEditShell());
557 SwTextNode* pTitleNode = pShell->GetCursor()->GetPointNode().GetTextNode();
558 SwNodeIndex aIdx(*pTitleNode);
559 // skip the title
560 pDoc->GetNodes().GoNext(&aIdx);
562 // skip the first header. No attributes there.
563 // next node should contain superscript
564 SwTextNode* pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
565 CPPUNIT_ASSERT(pNext->HasHints());
566 sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
567 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
569 // next node should contain subscript
570 pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
571 CPPUNIT_ASSERT(pNext->HasHints());
572 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
573 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
576 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf99689TableOfFigures)
578 createSwDoc("tdf99689_figures.odt");
579 SwDoc* pDoc = getSwDoc();
580 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
581 pWrtShell->GotoNextTOXBase();
582 const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
583 pWrtShell->UpdateTableOf(*pTOXBase);
584 SwCursorShell* pShell(pDoc->GetEditShell());
585 SwTextNode* pTitleNode = pShell->GetCursor()->GetPointNode().GetTextNode();
586 SwNodeIndex aIdx(*pTitleNode);
588 // skip the title
589 // next node should contain subscript
590 SwTextNode* pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
591 CPPUNIT_ASSERT(pNext->HasHints());
592 sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
593 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
595 // next node should contain superscript
596 pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
597 CPPUNIT_ASSERT(pNext->HasHints());
598 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
599 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
602 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf99689TableOfTables)
604 createSwDoc("tdf99689_tables.odt");
605 SwDoc* pDoc = getSwDoc();
606 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
607 pWrtShell->GotoNextTOXBase();
608 const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
609 pWrtShell->UpdateTableOf(*pTOXBase);
610 SwCursorShell* pShell(pDoc->GetEditShell());
611 SwTextNode* pTitleNode = pShell->GetCursor()->GetPointNode().GetTextNode();
612 SwNodeIndex aIdx(*pTitleNode);
614 // skip the title
615 // next node should contain superscript
616 SwTextNode* pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
617 CPPUNIT_ASSERT(pNext->HasHints());
618 sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
619 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
621 // next node should contain subscript
622 pNext = static_cast<SwTextNode*>(pDoc->GetNodes().GoNext(&aIdx));
623 CPPUNIT_ASSERT(pNext->HasHints());
624 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
625 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
628 // tdf#112448: Fix: take correct line height
630 // When line metrics is not calculated we need to call CalcRealHeight()
631 // before usage of the Height() and GetRealHeight().
632 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112448)
634 createSwDoc("tdf112448.odt");
636 // check actual number of line breaks in the paragraph
637 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
638 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout", 2);
641 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113790)
643 createSwDoc("tdf113790.docx");
644 SwDoc* pDoc = getSwDoc();
645 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
646 // Create the clipboard document.
647 SwDoc aClipboard;
648 aClipboard.SetClipBoard(true);
650 // Go to fourth line - to "ABCD" bulleted list item
651 pWrtShell->Down(/*bSelect=*/false, 4);
652 pWrtShell->SelPara(nullptr);
653 CPPUNIT_ASSERT_EQUAL(OUString("ABCD"), pWrtShell->GetSelText());
654 pWrtShell->Copy(aClipboard);
656 // Go down to next-to-last (empty) line above "Title3"
657 pWrtShell->Down(/*bSelect=*/false, 4);
658 pWrtShell->Paste(aClipboard);
660 // Save it as DOCX & load it again
661 saveAndReload("Office Open XML Text");
662 CPPUNIT_ASSERT(dynamic_cast<SwXTextDocument*>(mxComponent.get()));
665 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157937)
667 createSwDoc("tdf130088.docx");
668 SwDoc* pDoc = getSwDoc();
669 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
671 // select paragraph
672 pWrtShell->SelPara(nullptr);
674 // enable redlining
675 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
676 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
677 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
679 // show changes
680 CPPUNIT_ASSERT_MESSAGE(
681 "redlines should be visible",
682 IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
684 // cycle case with change tracking
685 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
686 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
688 // This resulted freezing
689 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
692 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157988)
694 createSwDoc("tdf130088.docx");
695 SwDoc* pDoc = getSwDoc();
697 // select the second word
698 dispatchCommand(mxComponent, ".uno:GoToNextWord", {});
699 dispatchCommand(mxComponent, ".uno:SelectWord", {});
701 // enable redlining
702 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
703 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
704 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
706 // show changes
707 CPPUNIT_ASSERT_MESSAGE(
708 "redlines should be visible",
709 IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
711 // cycle case with change tracking
713 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
715 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSodales"));
717 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
719 // This was false (missing revert of the tracked change)
720 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
722 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
724 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSODALES"));
726 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
728 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
730 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
732 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSodales"));
734 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
736 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
738 // tdf#141198 cycle case without selection: the word under the cursor
740 dispatchCommand(mxComponent, ".uno:Escape", {});
742 dispatchCommand(mxComponent, ".uno:GoRight", {});
744 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
746 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSODALES"));
748 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
750 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
752 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
754 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSodales"));
756 dispatchCommand(mxComponent, ".uno:ChangeCaseRotateCase", {});
758 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
761 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf108048)
763 createSwDoc();
765 uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({
766 { "Kind", uno::Any(sal_Int16(3)) },
767 { "TemplateName", uno::Any(OUString("Default Page Style")) },
768 { "PageNumber", uno::Any(sal_uInt16(6)) }, // Even number to avoid auto-inserted blank page
769 { "PageNumberFilled", uno::Any(true) },
771 dispatchCommand(mxComponent, ".uno:InsertBreak", aPropertyValues);
772 CPPUNIT_ASSERT_EQUAL(2, getParagraphs());
773 CPPUNIT_ASSERT_EQUAL(2, getPages());
775 // The inserted page must have page number set to 6
776 uno::Reference<text::XTextRange> xPara = getParagraph(2);
777 sal_uInt16 nPageNumber = getProperty<sal_uInt16>(xPara, "PageNumberOffset");
778 CPPUNIT_ASSERT_EQUAL(sal_uInt16(6), nPageNumber);
781 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113481)
783 createSwDoc("tdf113481-IVS.odt");
784 SwDoc* pDoc = getSwDoc();
785 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
787 // One backspace should completely remove the CJK ideograph variation sequence
788 pWrtShell->EndPara();
789 // Before: U+8FBA U+E0102. After: empty
790 pWrtShell->DelLeft();
791 const uno::Reference<text::XTextRange> xPara1 = getParagraph(1);
792 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xPara1->getString().getLength());
794 // In case that weak script is treated as CJK script, remove one character.
795 pWrtShell->Down(false);
796 pWrtShell->EndPara();
797 // Before: U+4E2D U+2205 U+FE00. After: U+4E2D U+2205
798 if (pWrtShell->GetScriptType() == SvtScriptType::ASIAN)
800 pWrtShell->DelLeft();
801 const uno::Reference<text::XTextRange> xPara2 = getParagraph(2);
802 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xPara2->getString().getLength());
803 CPPUNIT_ASSERT_EQUAL(u'\x2205', xPara2->getString()[1]);
806 // Characters of other scripts, remove one character.
807 pWrtShell->Down(false);
808 pWrtShell->EndPara();
809 // Before: U+1820 U+180B. After: U+1820
810 pWrtShell->DelLeft();
811 const uno::Reference<text::XTextRange> xPara3 = getParagraph(3);
812 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xPara3->getString().getLength());
813 CPPUNIT_ASSERT_EQUAL(u'\x1820', xPara3->getString()[0]);
816 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf115013)
818 const OUString sColumnName("Name with spaces, \"quotes\" and \\backslashes");
820 utl::TempFileNamed aTempDir(nullptr, true);
821 aTempDir.EnableKillingFile();
822 const OUString aWorkDir = aTempDir.GetURL();
824 //create new writer document
825 createSwDoc();
826 SwDoc* pDoc = getSwDoc();
829 // Load and register data source
830 OUString sDataSource
831 = SwDBManager::LoadAndRegisterDataSource(createFileURL(u"datasource.ods"), &aWorkDir);
832 CPPUNIT_ASSERT(!sDataSource.isEmpty());
834 // Insert a new field type for the mailmerge field
835 SwDBData aDBData;
836 aDBData.sDataSource = sDataSource;
837 aDBData.sCommand = "Sheet1";
838 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
839 CPPUNIT_ASSERT(pWrtShell);
840 SwDBFieldType* pFieldType = static_cast<SwDBFieldType*>(
841 pWrtShell->InsertFieldType(SwDBFieldType(pDoc, sColumnName, aDBData)));
842 CPPUNIT_ASSERT(pFieldType);
844 // Insert the field into document
845 SwDBField aField(pFieldType);
846 pWrtShell->InsertField2(aField);
848 // Save it as DOCX & load it again
849 saveAndReload("Office Open XML Text");
850 pDoc = getSwDoc();
851 CPPUNIT_ASSERT(pDoc);
852 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
853 CPPUNIT_ASSERT(pWrtShell);
854 SwPaM* pCursor = pDoc->GetEditShell()->GetCursor();
855 CPPUNIT_ASSERT(pCursor);
857 // Get the field at the beginning of the document
858 SwDBField* pField = dynamic_cast<SwDBField*>(SwCursorShell::GetFieldAtCursor(pCursor, true));
859 CPPUNIT_ASSERT(pField);
860 OUString sColumn = static_cast<SwDBFieldType*>(pField->GetTyp())->GetColumnName();
861 // The column name must come correct after round trip
862 CPPUNIT_ASSERT_EQUAL(sColumnName, sColumn);
865 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf115065)
867 // In the document, the tables have table style assigned
868 // Source table (first one) has two rows;
869 // destination (second one) has only one row
870 createSwDoc("tdf115065.odt");
871 SwDoc* pDoc = getSwDoc();
872 CPPUNIT_ASSERT(pDoc);
873 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
874 CPPUNIT_ASSERT(pWrtShell);
876 pWrtShell->GotoTable("Table2");
877 SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
878 // Destination point is the middle of the first cell of second table
879 Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
881 pWrtShell->GotoTable("Table1");
882 aRect = pWrtShell->GetCurrFrame()->getFrameArea();
883 // Source point is the middle of the first cell of first table
884 Point ptFrom(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
886 pWrtShell->SelTableCol();
887 // The copy operation (or closing document after that) segfaulted
888 pWrtShell->Copy(*pWrtShell, ptFrom, ptTo);
891 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf84806_MovingMultipleTableRows)
893 // Moving of multiple table rows.
894 // Source table (first one) has two rows;
895 // destination (second one) has only one row
896 createSwDoc("tdf115065.odt");
897 SwDoc* pDoc = getSwDoc();
898 CPPUNIT_ASSERT(pDoc);
899 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
900 CPPUNIT_ASSERT(pWrtShell);
902 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
903 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
904 uno::UNO_QUERY);
905 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
906 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
907 CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
908 CPPUNIT_ASSERT(xTableNames->hasByName("Table2"));
909 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName("Table1"), uno::UNO_QUERY);
910 uno::Reference<text::XTextTable> xTable2(xTableNames->getByName("Table2"), uno::UNO_QUERY);
911 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
912 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2->getRows()->getCount());
914 // without redlining
915 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
916 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
918 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
920 pWrtShell->GotoTable("Table2");
921 SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
922 // Destination point is the middle of the first cell of second table
923 Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
925 // Move rows of the first table into the second table
926 pWrtShell->GotoTable("Table1");
927 pWrtShell->SelTable();
928 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
929 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
931 // This was 2 tables
932 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
933 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());
935 // Undo results 2 tables
936 rUndoManager.Undo();
937 uno::Reference<container::XIndexAccess> xTables2(xTablesSupplier->getTextTables(),
938 uno::UNO_QUERY);
939 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables2->getCount());
940 uno::Reference<text::XTextTable> xTable1b(xTableNames->getByName("Table1"), uno::UNO_QUERY);
941 uno::Reference<text::XTextTable> xTable2b(xTableNames->getByName("Table2"), uno::UNO_QUERY);
942 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
943 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());
945 // FIXME assert with Redo()
948 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf147181_TrackedMovingOfMultipleTableRows)
950 // Tracked moving of multiple table rows.
951 // Source table (first one) has two rows;
952 // destination (second one) has only one row
953 createSwDoc("tdf115065.odt");
954 SwDoc* pDoc = getSwDoc();
955 CPPUNIT_ASSERT(pDoc);
956 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
957 CPPUNIT_ASSERT(pWrtShell);
959 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
960 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
961 uno::UNO_QUERY);
962 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
963 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
964 CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
965 CPPUNIT_ASSERT(xTableNames->hasByName("Table2"));
966 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName("Table1"), uno::UNO_QUERY);
967 uno::Reference<text::XTextTable> xTable2(xTableNames->getByName("Table2"), uno::UNO_QUERY);
968 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
969 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2->getRows()->getCount());
971 // FIXME: doesn't work with empty rows, yet
972 pWrtShell->Insert("x");
973 pWrtShell->Down(false);
974 pWrtShell->Insert("x");
976 // enable redlining
977 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
978 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
979 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
981 // show changes
982 CPPUNIT_ASSERT_MESSAGE(
983 "redlines should be visible",
984 IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
986 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
988 pWrtShell->GotoTable("Table2");
989 SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
990 // Destination point is the middle of the first cell of second table
991 Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
993 // Move rows of the first table into the second table
994 pWrtShell->GotoTable("Table1");
995 pWrtShell->SelTable();
996 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
997 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
999 // still 2 tables, but the second one has got 3 rows
1000 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
1001 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
1002 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());
1004 // accept changes results 1 table (removing moved table)
1005 dispatchCommand(mxComponent, ".uno:AcceptAllTrackedChanges", {});
1006 uno::Reference<container::XIndexAccess> xTables2(xTablesSupplier->getTextTables(),
1007 uno::UNO_QUERY);
1008 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables2->getCount());
1009 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());
1011 // Undo results 2 tables
1012 rUndoManager.Undo();
1013 rUndoManager.Undo();
1014 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables2->getCount());
1015 uno::Reference<text::XTextTable> xTable1b(xTableNames->getByName("Table1"), uno::UNO_QUERY);
1016 uno::Reference<text::XTextTable> xTable2b(xTableNames->getByName("Table2"), uno::UNO_QUERY);
1017 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
1018 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());
1020 // reject changes results 2 table again, with the original row counts
1021 dispatchCommand(mxComponent, ".uno:RejectAllTrackedChanges", {});
1022 uno::Reference<container::XIndexAccess> xTables3(xTablesSupplier->getTextTables(),
1023 uno::UNO_QUERY);
1024 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables3->getCount());
1025 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
1026 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());
1029 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157492_TrackedMovingRow)
1031 createSwDoc();
1032 SwDoc* pDoc = getSwDoc();
1033 CPPUNIT_ASSERT(pDoc);
1034 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1035 CPPUNIT_ASSERT(pWrtShell);
1037 // Create a table
1038 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1039 (void)&pWrtShell->InsertTable(TableOpt, 4, 3);
1041 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1042 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1043 CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
1044 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName("Table1"), uno::UNO_QUERY);
1045 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
1046 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());
1048 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1050 // fill table with data
1051 for (int i = 0; i < 3; ++i)
1053 pWrtShell->Insert("x");
1054 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RIGHT);
1057 Scheduler::ProcessEventsToIdle();
1059 uno::Reference<text::XTextRange> xCellA1(xTable1->getCellByName("A1"), uno::UNO_QUERY);
1060 xCellA1->setString("A1");
1061 uno::Reference<text::XTextRange> xCellB1(xTable1->getCellByName("B1"), uno::UNO_QUERY);
1062 xCellB1->setString("B1");
1063 uno::Reference<text::XTextRange> xCellC1(xTable1->getCellByName("C1"), uno::UNO_QUERY);
1064 xCellC1->setString("C1");
1066 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1067 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[1]/txt", "A1");
1068 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[2]/txt", "B1");
1069 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[3]/txt", "C1");
1071 // enable redlining
1072 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
1073 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
1074 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1076 // Move first column of the table before the third column by drag & drop
1077 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1078 SwFrame* pPage = pLayout->Lower();
1079 SwFrame* pBody = pPage->GetLower();
1080 SwFrame* pTable = pBody->GetLower();
1081 SwFrame* pRow1 = pTable->GetLower();
1082 SwFrame* pCellA1 = pRow1->GetLower();
1083 SwFrame* pRow3 = pRow1->GetNext()->GetNext();
1084 SwFrame* pCellA3 = pRow3->GetLower();
1085 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1086 const SwRect& rCellA3Rect = pCellA3->getFrameArea();
1087 Point ptTo(rCellA3Rect.Left() + rCellA3Rect.Width() / 2,
1088 rCellA3Rect.Top() + rCellA3Rect.Height() / 2);
1089 // select first table row by using the middle point of the left border of row 1
1090 Point ptRow(rCellA1Rect.Left() - 5, rCellA1Rect.Top() + rCellA1Rect.Height() / 2);
1091 pWrtShell->SelectTableRowCol(ptRow);
1093 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
1095 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
1097 // reject changes results 4 rows again, not 5
1098 dispatchCommand(mxComponent, ".uno:RejectAllTrackedChanges", {});
1100 xTableNames = xTablesSupplier->getTextTables();
1101 CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
1102 uno::Reference<text::XTextTable> xTable2(xTableNames->getByName("Table1"), uno::UNO_QUERY);
1103 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getColumns()->getCount());
1104 // This was 5 (moving row without change tracking)
1105 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable2->getRows()->getCount());
1108 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf154599_MovingColumn)
1110 createSwDoc();
1111 SwDoc* pDoc = getSwDoc();
1112 CPPUNIT_ASSERT(pDoc);
1113 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1114 CPPUNIT_ASSERT(pWrtShell);
1116 // Create a table with less columns than rows
1117 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1118 (void)&pWrtShell->InsertTable(TableOpt, 4, 3);
1120 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1121 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1122 CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
1123 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName("Table1"), uno::UNO_QUERY);
1124 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
1125 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());
1127 // without redlining
1128 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
1129 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1131 // Move first column of the table before the third column by drag & drop
1133 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1134 SwFrame* pPage = pLayout->Lower();
1135 SwFrame* pBody = pPage->GetLower();
1136 SwFrame* pTable = pBody->GetLower();
1137 SwFrame* pRow1 = pTable->GetLower();
1138 SwFrame* pCellA1 = pRow1->GetLower();
1139 SwFrame* pCellC1 = pCellA1->GetNext()->GetNext();
1140 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1141 const SwRect& rCellC1Rect = pCellC1->getFrameArea();
1142 Point ptTo(rCellC1Rect.Left() + rCellC1Rect.Width() / 2,
1143 rCellC1Rect.Top() + rCellC1Rect.Height() / 2);
1144 // select first table column by using the middle point of the top border of column A
1145 Point ptColumn(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() - 5);
1146 pWrtShell->SelectTableRowCol(ptColumn);
1148 // This crashed here before the fix.
1149 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
1151 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
1153 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
1154 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());
1157 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf155846_MovingColumn)
1159 createSwDoc();
1160 SwDoc* pDoc = getSwDoc();
1161 CPPUNIT_ASSERT(pDoc);
1162 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1163 CPPUNIT_ASSERT(pWrtShell);
1165 // Create a table
1166 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1167 (void)&pWrtShell->InsertTable(TableOpt, 4, 3);
1169 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1170 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1171 CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
1172 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName("Table1"), uno::UNO_QUERY);
1173 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
1174 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());
1176 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1178 // fill table with data
1179 for (int i = 0; i < 4; ++i)
1181 pWrtShell->Insert("x");
1182 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_DOWN);
1185 Scheduler::ProcessEventsToIdle();
1187 uno::Reference<text::XTextRange> xCellA1(xTable1->getCellByName("A1"), uno::UNO_QUERY);
1188 xCellA1->setString("A1");
1189 uno::Reference<text::XTextRange> xCellA2(xTable1->getCellByName("A2"), uno::UNO_QUERY);
1190 xCellA2->setString("A2");
1191 uno::Reference<text::XTextRange> xCellA3(xTable1->getCellByName("A3"), uno::UNO_QUERY);
1192 xCellA3->setString("A3");
1193 uno::Reference<text::XTextRange> xCellA4(xTable1->getCellByName("A4"), uno::UNO_QUERY);
1194 xCellA4->setString("A4");
1196 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1197 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[1]/txt", "A1");
1198 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[2]/cell[1]/txt", "A2");
1199 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[3]/cell[1]/txt", "A3");
1200 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[4]/cell[1]/txt", "A4");
1202 // enable redlining
1203 dispatchCommand(mxComponent, ".uno:TrackChanges", {});
1204 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
1205 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1207 // Move first column of the table before the third column by drag & drop
1208 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1209 SwFrame* pPage = pLayout->Lower();
1210 SwFrame* pBody = pPage->GetLower();
1211 SwFrame* pTable = pBody->GetLower();
1212 SwFrame* pRow1 = pTable->GetLower();
1213 SwFrame* pCellA1 = pRow1->GetLower();
1214 SwFrame* pCellC1 = pCellA1->GetNext()->GetNext();
1215 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1216 const SwRect& rCellC1Rect = pCellC1->getFrameArea();
1217 Point ptTo(rCellC1Rect.Left() + rCellC1Rect.Width() / 2,
1218 rCellC1Rect.Top() + rCellC1Rect.Height() / 2);
1219 // select first table column by using the middle point of the top border of column A
1220 Point ptColumn(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() - 5);
1221 pWrtShell->SelectTableRowCol(ptColumn);
1223 // This crashed here before the fix.
1224 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
1226 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
1228 // reject changes results 3 columns again, not 4
1229 dispatchCommand(mxComponent, ".uno:RejectAllTrackedChanges", {});
1231 xTableNames = xTablesSupplier->getTextTables();
1232 CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
1233 uno::Reference<text::XTextTable> xTable2(xTableNames->getByName("Table1"), uno::UNO_QUERY);
1234 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable2->getRows()->getCount());
1235 // This was 4 (moving column without change tracking)
1236 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getColumns()->getCount());
1239 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf154771_MovingMultipleColumns)
1241 createSwDoc();
1242 SwDoc* pDoc = getSwDoc();
1243 CPPUNIT_ASSERT(pDoc);
1244 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1245 CPPUNIT_ASSERT(pWrtShell);
1247 // Create a table with less columns than rows
1248 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1249 (void)&pWrtShell->InsertTable(TableOpt, 5, 4);
1251 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1252 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1253 CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
1254 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName("Table1"), uno::UNO_QUERY);
1255 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xTable1->getRows()->getCount());
1256 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getColumns()->getCount());
1258 // without redlining
1259 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
1260 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1262 // Move first two columns of the table before column D by drag & drop
1264 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1265 SwFrame* pPage = pLayout->Lower();
1266 SwFrame* pBody = pPage->GetLower();
1267 SwFrame* pTable = pBody->GetLower();
1268 SwFrame* pRow1 = pTable->GetLower();
1269 SwFrame* pCellA1 = pRow1->GetLower();
1270 SwFrame* pCellB1 = pCellA1->GetNext();
1271 SwFrame* pCellD1 = pCellB1->GetNext()->GetNext();
1272 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1273 const SwRect& rCellB1Rect = pCellB1->getFrameArea();
1274 const SwRect& rCellD1Rect = pCellD1->getFrameArea();
1275 Point ptTo(rCellD1Rect.Left() + rCellD1Rect.Width() / 2,
1276 rCellD1Rect.Top() + rCellD1Rect.Height() / 2);
1277 // select first two table columns by using
1278 // the middle point of the top border of column A
1279 // and middle point of the top border of column B
1280 Point ptColumnA(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() - 5);
1281 const Point ptColumnB(rCellB1Rect.Left() + rCellB1Rect.Width() / 2, rCellB1Rect.Top() - 5);
1282 pWrtShell->SelectTableRowCol(ptColumnA, &ptColumnB);
1284 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
1285 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
1287 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xTable1->getRows()->getCount());
1288 // This was 5 before the fix (only the first selected column was moved, the
1289 // other ones were copied instead of moving)
1290 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getColumns()->getCount());
1293 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf115132)
1295 createSwDoc();
1296 SwDoc* pDoc = getSwDoc();
1297 CPPUNIT_ASSERT(pDoc);
1298 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1299 CPPUNIT_ASSERT(pWrtShell);
1301 std::vector<OUString> vTestTableNames;
1303 // Create an empty paragraph that will separate first table from the rest
1304 pWrtShell->SplitNode();
1305 pWrtShell->StartOfSection();
1306 // Create a table at the start of document body
1307 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1308 const SwTable* pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
1309 const SwTableFormat* pFormat = pTable->GetFrameFormat();
1310 CPPUNIT_ASSERT(pFormat);
1311 vTestTableNames.push_back(pFormat->GetName());
1312 pWrtShell->EndOfSection();
1313 // Create a table after a paragraph
1314 pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
1315 pFormat = pTable->GetFrameFormat();
1316 CPPUNIT_ASSERT(pFormat);
1317 vTestTableNames.push_back(pFormat->GetName());
1318 // Create a table immediately after the previous
1319 pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
1320 pFormat = pTable->GetFrameFormat();
1321 CPPUNIT_ASSERT(pFormat);
1322 vTestTableNames.push_back(pFormat->GetName());
1323 // Create a nested table in the middle of last row
1324 pWrtShell->GotoTable(vTestTableNames.back());
1325 for (int i = 0; i < 4; ++i)
1326 pWrtShell->GoNextCell(false);
1327 pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
1328 pFormat = pTable->GetFrameFormat();
1329 CPPUNIT_ASSERT(pFormat);
1330 vTestTableNames.push_back(pFormat->GetName());
1332 // Now check that in any cell in all tables we don't go out of a cell
1333 // using Delete or Backspace. We test cases when a table is the first node;
1334 // when we are in a first/middle/last cell in a row; when there's a paragraph
1335 // before/after this cell; when there's another table before/after this cell;
1336 // in nested table.
1337 for (const auto& rTableName : vTestTableNames)
1339 pWrtShell->GotoTable(rTableName);
1342 const SwStartNode* pNd = pWrtShell->GetCursor()->GetPointNode().FindTableBoxStartNode();
1343 pWrtShell->DelRight();
1344 CPPUNIT_ASSERT_EQUAL(pNd,
1345 pWrtShell->GetCursor()->GetPointNode().FindTableBoxStartNode());
1346 pWrtShell->DelLeft();
1347 CPPUNIT_ASSERT_EQUAL(pNd,
1348 pWrtShell->GetCursor()->GetPointNode().FindTableBoxStartNode());
1349 } while (pWrtShell->GoNextCell(false));
1353 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testXDrawPagesSupplier)
1355 createSwDoc();
1356 uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
1357 CPPUNIT_ASSERT_MESSAGE("XDrawPagesSupplier interface is unavailable", xDrawPagesSupplier.is());
1358 uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
1359 CPPUNIT_ASSERT(xDrawPages.is());
1360 CPPUNIT_ASSERT_EQUAL_MESSAGE("There must be only a single DrawPage in Writer documents",
1361 sal_Int32(1), xDrawPages->getCount());
1362 uno::Any aDrawPage = xDrawPages->getByIndex(0);
1363 uno::Reference<drawing::XDrawPage> xDrawPageFromXDrawPages(aDrawPage, uno::UNO_QUERY);
1364 CPPUNIT_ASSERT(xDrawPageFromXDrawPages.is());
1366 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
1367 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
1368 CPPUNIT_ASSERT_EQUAL_MESSAGE(
1369 "The DrawPage accessed using XDrawPages must be the same as using XDrawPageSupplier",
1370 xDrawPage.get(), xDrawPageFromXDrawPages.get());
1373 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf116403)
1375 createSwDoc("tdf116403-considerborders.odt");
1376 SwDoc* pDoc = getSwDoc();
1377 // Check that before ToX update, the tab stop position is the old one
1378 uno::Reference<text::XTextRange> xParagraph = getParagraph(2, "1\t1");
1379 auto aTabs = getProperty<uno::Sequence<style::TabStop>>(xParagraph, "ParaTabStops");
1380 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aTabs.getLength());
1381 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(17000), aTabs[0].Position);
1383 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1384 const SwTOXBase* pTOX = pWrtShell->GetTOX(0);
1385 CPPUNIT_ASSERT(pTOX);
1386 pWrtShell->UpdateTableOf(*pTOX);
1388 xParagraph = getParagraph(2, "1\t1");
1389 aTabs = getProperty<uno::Sequence<style::TabStop>>(xParagraph, "ParaTabStops");
1390 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aTabs.getLength());
1391 // This was still 17000, refreshing ToX didn't take borders spacings and widths into account
1392 CPPUNIT_ASSERT_EQUAL_MESSAGE("Page borders must be considered for right-aligned tabstop",
1393 static_cast<sal_Int32>(17000 - 2 * 500 - 2 * 1),
1394 aTabs[0].Position);
1397 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testHtmlCopyImages)
1399 // Load a document with an image.
1400 createSwDoc("image.odt");
1401 SwDoc* pDoc = getSwDoc();
1403 // Trigger the copy part of HTML copy&paste.
1404 WriterRef xWrt = new SwHTMLWriter(/*rBaseURL=*/OUString());
1405 CPPUNIT_ASSERT(xWrt.is());
1407 xWrt->m_bWriteClipboardDoc = true;
1408 xWrt->m_bWriteOnlyFirstTable = false;
1409 xWrt->SetShowProgress(false);
1411 SvFileStream aStream(maTempFile.GetURL(), StreamMode::WRITE | StreamMode::TRUNC);
1412 SwWriter aWrt(aStream, *pDoc);
1413 aWrt.Write(xWrt);
1415 htmlDocUniquePtr pHtmlDoc = parseHtml(maTempFile);
1416 CPPUNIT_ASSERT(pHtmlDoc);
1418 // This failed, image was lost during HTML copy.
1419 OUString aImage = getXPath(pHtmlDoc, "/html/body/p/img", "src");
1420 // Also make sure that the image is not embedded (e.g. Word doesn't handle
1421 // embedded images).
1422 CPPUNIT_ASSERT(aImage.startsWith("file:///"));
1425 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf116789)
1427 createSwDoc("tdf116789.fodt");
1428 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
1429 uno::Reference<text::XText> xText1;
1430 uno::Reference<text::XText> xText2;
1432 uno::Reference<text::XTextContent> xBookmark(
1433 xBookmarksSupplier->getBookmarks()->getByName("Bookmark 1"), uno::UNO_QUERY);
1434 xText1 = xBookmark->getAnchor()->getText();
1437 uno::Reference<text::XTextContent> xBookmark(
1438 xBookmarksSupplier->getBookmarks()->getByName("Bookmark 1"), uno::UNO_QUERY);
1439 xText2 = xBookmark->getAnchor()->getText();
1441 // This failed, we got two different SwXCell for the same bookmark anchor text.
1442 CPPUNIT_ASSERT_EQUAL(xText1, xText2);
1445 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf91801)
1447 // Tests calculation with several user field variables without prior user fields
1448 createSwDoc("tdf91801.fodt");
1449 uno::Reference<text::XTextTable> xTable(getParagraphOrTable(1), uno::UNO_QUERY);
1450 uno::Reference<table::XCell> xCell(xTable->getCellByName("A1"));
1451 CPPUNIT_ASSERT_EQUAL(555.0, xCell->getValue());
1454 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf51223)
1456 createSwDoc();
1457 SwDoc* pDoc = getSwDoc();
1458 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1459 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
1460 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetPointNode().GetIndex();
1461 pWrtShell->Insert("i");
1462 pWrtShell->SplitNode(true);
1463 CPPUNIT_ASSERT_EQUAL(OUString("I"),
1464 static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
1465 rUndoManager.Undo();
1466 CPPUNIT_ASSERT_EQUAL(OUString("i"),
1467 static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
1470 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testFontEmbedding)
1472 #if HAVE_MORE_FONTS && !defined(MACOSX)
1473 createSwDoc("testFontEmbedding.odt");
1475 OString aContentBaseXpath("/office:document-content/office:font-face-decls");
1476 OString aSettingsBaseXpath("/office:document-settings/office:settings/config:config-item-set");
1478 xmlDocUniquePtr pXmlDoc;
1480 // Get document settings
1481 uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY_THROW);
1482 uno::Reference<beans::XPropertySet> xProps(
1483 xFactory->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY_THROW);
1485 // Check font embedding state
1486 CPPUNIT_ASSERT_EQUAL(false, xProps->getPropertyValue("EmbedFonts").get<bool>());
1487 CPPUNIT_ASSERT_EQUAL(false, xProps->getPropertyValue("EmbedOnlyUsedFonts").get<bool>());
1488 // Font scripts should be enabled by default, however this has no effect unless "EmbedOnlyUsedFonts" is enabled
1489 CPPUNIT_ASSERT_EQUAL(true, xProps->getPropertyValue("EmbedLatinScriptFonts").get<bool>());
1490 CPPUNIT_ASSERT_EQUAL(true, xProps->getPropertyValue("EmbedAsianScriptFonts").get<bool>());
1491 CPPUNIT_ASSERT_EQUAL(true, xProps->getPropertyValue("EmbedComplexScriptFonts").get<bool>());
1493 // CASE 1 - no font embedding enabled
1495 // Save the document
1496 save("writer8");
1497 CPPUNIT_ASSERT(maTempFile.IsValid());
1499 // Check setting - No font embedding should be enabled
1500 pXmlDoc = parseExport("settings.xml");
1501 CPPUNIT_ASSERT(pXmlDoc);
1502 assertXPathContent(
1503 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedFonts']", "false");
1505 // Check content - No font-face-src nodes should be present
1506 pXmlDoc = parseExport("content.xml");
1507 CPPUNIT_ASSERT(pXmlDoc);
1509 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6);
1510 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']");
1511 assertXPath(
1512 pXmlDoc,
1513 aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 0);
1514 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']");
1515 assertXPath(pXmlDoc,
1516 aContentBaseXpath
1517 + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src",
1519 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']");
1520 assertXPath(pXmlDoc,
1521 aContentBaseXpath
1522 + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src",
1524 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']");
1525 assertXPath(pXmlDoc,
1526 aContentBaseXpath
1527 + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src",
1529 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']");
1530 assertXPath(pXmlDoc,
1531 aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 0);
1532 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']");
1533 assertXPath(pXmlDoc,
1534 aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 0);
1536 // CASE 2 - font embedding enabled, but embed used fonts disabled
1538 // Enable font embedding, disable embedding used font only
1539 xProps->setPropertyValue("EmbedFonts", uno::Any(true));
1540 xProps->setPropertyValue("EmbedOnlyUsedFonts", uno::Any(false));
1542 // Save the document again
1543 save("writer8");
1544 CPPUNIT_ASSERT(maTempFile.IsValid());
1546 // Check setting - font embedding should be enabled + embed only used fonts and scripts
1547 pXmlDoc = parseExport("settings.xml");
1548 CPPUNIT_ASSERT(pXmlDoc);
1549 assertXPathContent(
1550 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedFonts']", "true");
1551 assertXPathContent(
1552 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedOnlyUsedFonts']",
1553 "false");
1554 assertXPathContent(
1555 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedLatinScriptFonts']",
1556 "true");
1557 assertXPathContent(
1558 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedAsianScriptFonts']",
1559 "true");
1560 assertXPathContent(
1561 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedComplexScriptFonts']",
1562 "true");
1564 // Check content - font-face-src should be present only for "Liberation Sans" fonts
1566 pXmlDoc = parseExport("content.xml");
1567 CPPUNIT_ASSERT(pXmlDoc);
1569 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6);
1570 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']");
1571 assertXPath(
1572 pXmlDoc,
1573 aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 1);
1574 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']");
1575 assertXPath(pXmlDoc,
1576 aContentBaseXpath
1577 + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src",
1579 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']");
1580 assertXPath(pXmlDoc,
1581 aContentBaseXpath
1582 + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src",
1584 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']");
1585 assertXPath(pXmlDoc,
1586 aContentBaseXpath
1587 + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src",
1589 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']");
1590 assertXPath(pXmlDoc,
1591 aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 1);
1592 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']");
1593 assertXPath(pXmlDoc,
1594 aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 1);
1596 // CASE 3 - font embedding enabled, embed only used fonts enabled
1598 // Enable font embedding and setting to embed used fonts only
1599 xProps->setPropertyValue("EmbedFonts", uno::Any(true));
1600 xProps->setPropertyValue("EmbedOnlyUsedFonts", uno::Any(true));
1601 xProps->setPropertyValue("EmbedLatinScriptFonts", uno::Any(true));
1602 xProps->setPropertyValue("EmbedAsianScriptFonts", uno::Any(true));
1603 xProps->setPropertyValue("EmbedComplexScriptFonts", uno::Any(true));
1605 // Save the document again
1606 save("writer8");
1607 CPPUNIT_ASSERT(maTempFile.IsValid());
1609 // Check setting - font embedding should be enabled + embed only used fonts and scripts
1610 pXmlDoc = parseExport("settings.xml");
1611 CPPUNIT_ASSERT(pXmlDoc);
1612 assertXPathContent(
1613 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedFonts']", "true");
1614 assertXPathContent(
1615 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedOnlyUsedFonts']",
1616 "true");
1617 assertXPathContent(
1618 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedLatinScriptFonts']",
1619 "true");
1620 assertXPathContent(
1621 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedAsianScriptFonts']",
1622 "true");
1623 assertXPathContent(
1624 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedComplexScriptFonts']",
1625 "true");
1627 // Check content - font-face-src should be present only for "Liberation Sans" fonts
1629 pXmlDoc = parseExport("content.xml");
1630 CPPUNIT_ASSERT(pXmlDoc);
1632 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6);
1633 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']");
1634 assertXPath(
1635 pXmlDoc,
1636 aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 0);
1637 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']");
1638 assertXPath(pXmlDoc,
1639 aContentBaseXpath
1640 + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src",
1642 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']");
1643 assertXPath(pXmlDoc,
1644 aContentBaseXpath
1645 + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src",
1647 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']");
1648 assertXPath(pXmlDoc,
1649 aContentBaseXpath
1650 + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src",
1652 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']");
1653 assertXPath(pXmlDoc,
1654 aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 1);
1655 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']");
1656 assertXPath(pXmlDoc,
1657 aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 0);
1658 #endif
1661 // Unit test for fix inconsistent bookmark behavior around at-char/as-char anchored frames
1663 // We have a placeholder character in the sw doc model for as-char anchored frames,
1664 // so it's possible to have a bookmark before/after the frame or a non-collapsed bookmark
1665 // which covers the frame. The same is not true for at-char anchored frames,
1666 // where the anchor points to a doc model position, but there is no placeholder character.
1667 // If a bookmark is created covering the start and end of the anchor of the frame,
1668 // internally we create a collapsed bookmark which has the same position as the anchor of the frame.
1669 // When this doc model is handled by SwXParagraph::createEnumeration(),
1670 // first the frame and then the bookmark is appended to the text portion enumeration,
1671 // so your bookmark around the frame is turned into a collapsed bookmark after the frame.
1672 // (The same happens when we roundtrip an ODT document representing this doc model.)
1674 // Fix the problem by inserting collapsed bookmarks with affected anchor positions
1675 // (same position is the anchor for an at-char frame) into the enumeration in two stages:
1676 // first the start of them before frames and then the end of them + other bookmarks.
1677 // This way UNO API users get their non-collapsed bookmarks around at-char anchored frames,
1678 // similar to as-char ones.
1679 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testInconsistentBookmark)
1681 // create test document with text and bookmark
1683 createSwDoc("testInconsistentBookmark.ott");
1684 SwDoc* pDoc = getSwDoc();
1685 IDocumentMarkAccess& rIDMA(*pDoc->getIDocumentMarkAccess());
1686 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
1687 SwCursor aPaM(SwPosition(aIdx), nullptr);
1688 aPaM.SetMark();
1689 aPaM.MovePara(GoCurrPara, fnParaStart);
1690 aPaM.MovePara(GoCurrPara, fnParaEnd);
1691 rIDMA.makeMark(aPaM, "Mark", IDocumentMarkAccess::MarkType::BOOKMARK,
1692 ::sw::mark::InsertMode::New);
1693 aPaM.Exchange();
1694 aPaM.DeleteMark();
1697 // save document and verify the bookmark scoup
1699 // save document
1700 save("writer8");
1702 // load only content.xml
1703 xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
1704 const OString aPath("/office:document-content/office:body/office:text/text:p");
1706 const int pos1 = getXPathPosition(pXmlDoc, aPath, "bookmark-start");
1707 const int pos2 = getXPathPosition(pXmlDoc, aPath, "control");
1708 const int pos3 = getXPathPosition(pXmlDoc, aPath, "bookmark-end");
1710 CPPUNIT_ASSERT_GREATER(pos1, pos2);
1711 CPPUNIT_ASSERT_GREATER(pos2, pos3);
1715 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSpellOnlineParameter)
1717 createSwDoc();
1718 SwDoc* pDoc = getSwDoc();
1719 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1720 const SwViewOption* pOpt = pWrtShell->GetViewOptions();
1721 bool bSet = pOpt->IsOnlineSpell();
1723 uno::Sequence<beans::PropertyValue> params
1724 = comphelper::InitPropertySequence({ { "Enable", uno::Any(!bSet) } });
1725 dispatchCommand(mxComponent, ".uno:SpellOnline", params);
1726 CPPUNIT_ASSERT_EQUAL(!bSet, pOpt->IsOnlineSpell());
1728 // set the same state as now and we don't expect any change (no-toggle)
1729 params = comphelper::InitPropertySequence({ { "Enable", uno::Any(!bSet) } });
1730 dispatchCommand(mxComponent, ".uno:SpellOnline", params);
1731 CPPUNIT_ASSERT_EQUAL(!bSet, pOpt->IsOnlineSpell());
1734 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf124603)
1736 createSwDoc();
1737 SwDoc* pDoc = getSwDoc();
1738 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1739 const SwViewOption* pOpt = pWrtShell->GetViewOptions();
1740 uno::Sequence<beans::PropertyValue> params
1741 = comphelper::InitPropertySequence({ { "Enable", uno::Any(true) } });
1742 dispatchCommand(mxComponent, ".uno:SpellOnline", params);
1744 // Automatic Spell Checking is enabled
1746 CPPUNIT_ASSERT(pOpt->IsOnlineSpell());
1748 // check available en_US dictionary and test spelling with it
1749 uno::Reference<XLinguServiceManager2> xLngSvcMgr(GetLngSvcMgr_Impl());
1750 uno::Reference<XSpellChecker1> xSpell;
1751 xSpell.set(xLngSvcMgr->getSpellChecker(), UNO_QUERY);
1752 LanguageType eLang = LanguageTag::convertToLanguageType(lang::Locale("en", "US", OUString()));
1753 if (xSpell.is() && xSpell->hasLanguage(static_cast<sal_uInt16>(eLang)))
1755 // Type a correct word
1757 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1758 emulateTyping(*pTextDoc, u"the ");
1759 SwCursorShell* pShell(pDoc->GetEditShell());
1760 SwTextNode* pNode = pShell->GetCursor()->GetPointNode().GetTextNode();
1761 // no bad word
1762 CPPUNIT_ASSERT_EQUAL(static_cast<SwWrongList*>(nullptr), pNode->GetWrong());
1764 // Create a bad word from the good: "the" -> "thex"
1766 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1767 emulateTyping(*pTextDoc, u"x");
1768 // tdf#92036 pending spell checking
1769 bool bPending = !pNode->GetWrong() || !pNode->GetWrong()->Count();
1770 CPPUNIT_ASSERT(bPending);
1772 // Move right, leave the bad word
1774 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1775 // tdf#92036 still pending spell checking
1776 bPending = !pNode->GetWrong() || !pNode->GetWrong()->Count();
1777 CPPUNIT_ASSERT(bPending);
1779 // Move down to trigger spell checking
1781 pWrtShell->Down(/*bSelect=*/false, 1);
1782 Scheduler::ProcessEventsToIdle();
1783 CPPUNIT_ASSERT(pNode->GetWrong());
1784 // This was 0 (pending spell checking)
1785 CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pNode->GetWrong()->Count());
1789 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf65535)
1791 #if !defined(MACOSX)
1792 createSwDoc("tdf65535.fodt");
1793 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1794 SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell();
1795 const SwViewOption* pOpt = pWrtShell->GetViewOptions();
1796 uno::Sequence<beans::PropertyValue> params
1797 = comphelper::InitPropertySequence({ { "Enable", uno::Any(true) } });
1798 dispatchCommand(mxComponent, ".uno:SpellOnline", params);
1800 // Automatic Spell Checking is enabled
1802 CPPUNIT_ASSERT(pOpt->IsOnlineSpell());
1804 // check available en_US dictionary and test spelling with it
1805 uno::Reference<XLinguServiceManager2> xLngSvcMgr(GetLngSvcMgr_Impl());
1806 uno::Reference<XSpellChecker1> xSpell;
1807 xSpell.set(xLngSvcMgr->getSpellChecker(), UNO_QUERY);
1808 LanguageType eLang = LanguageTag::convertToLanguageType(lang::Locale("en", "US", OUString()));
1809 if (xSpell.is() && xSpell->hasLanguage(static_cast<sal_uInt16>(eLang)))
1811 // trigger online spell checking by (a few) spaces to be sure to get it
1813 emulateTyping(*pTextDoc, u" ");
1815 // FIXME: inserting a space before the bad word removes the red underline
1816 // Insert a second space to get the red underline (back)
1818 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1819 emulateTyping(*pTextDoc, u" ");
1821 // Select the bad word (right to left, as during right click)
1823 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 5, /*bBasicCall=*/false);
1824 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 4, /*bBasicCall=*/false);
1826 // choose the word "Baaed" from the spelling suggestions of the context menu
1828 SfxViewShell* pViewShell = SfxViewShell::Current();
1830 static const OUStringLiteral sApplyRule(u"Spelling_Baaed");
1831 SfxStringItem aApplyItem(FN_PARAM_1, sApplyRule);
1832 pViewShell->GetViewFrame().GetDispatcher()->ExecuteList(
1833 SID_SPELLCHECK_APPLY_SUGGESTION, SfxCallMode::SYNCHRON, { &aApplyItem });
1836 // check the replacement in the text
1838 CPPUNIT_ASSERT_EQUAL(OUString(" Baaed"), getParagraph(1)->getString());
1841 // check the remaining comment
1843 tools::JsonWriter aJsonWriter;
1844 pTextDoc->getPostIts(aJsonWriter);
1845 OString pChar = aJsonWriter.finishAndGetAsOString();
1846 std::stringstream aStream((std::string(pChar)));
1847 boost::property_tree::ptree aTree;
1848 boost::property_tree::read_json(aStream, aTree);
1849 OString sCommentText;
1850 for (const boost::property_tree::ptree::value_type& rValue : aTree.get_child("comments"))
1852 const boost::property_tree::ptree& rComment = rValue.second;
1853 sCommentText = OString(rComment.get<std::string>("text"));
1855 // This was false (lost comment with spelling replacement)
1856 CPPUNIT_ASSERT_EQUAL(OString("with comment"), sCommentText);
1857 #endif
1860 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testRedlineAutoCorrect)
1862 createSwDoc("redline-autocorrect.fodt");
1863 SwDoc* pDoc = getSwDoc();
1865 dispatchCommand(mxComponent, ".uno:GoToEndOfDoc", {});
1867 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1868 CPPUNIT_ASSERT(pWrtShell);
1869 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1871 // show tracked deletion with enabled change tracking
1872 RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
1873 CPPUNIT_ASSERT(nMode & (RedlineFlags::ShowDelete | RedlineFlags::ShowInsert));
1874 pWrtShell->SetRedlineFlags(nMode);
1875 CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);
1877 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
1878 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1880 emulateTyping(*pTextDoc, u" ");
1882 // tdf#83419 This was "Ts " removing the deletion of "t" silently by sentence capitalization
1883 OUString sReplaced("ts ");
1884 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1886 // hide delete redlines
1887 pWrtShell->SetRedlineFlags(nMode & ~RedlineFlags::ShowDelete);
1889 // repeat it with not visible redlining
1890 dispatchCommand(mxComponent, ".uno:Undo", {});
1892 emulateTyping(*pTextDoc, u" ");
1894 sReplaced = "S ";
1895 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1897 // show delete redlines
1898 pWrtShell->SetRedlineFlags(nMode);
1900 // This still keep the tracked deletion, capitalize only the visible text "s"
1901 // with tracked deletion of the original character
1902 sReplaced = "tsS ";
1903 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1905 // repeat it with visible redlining and word auto replacement of "tset"
1906 dispatchCommand(mxComponent, ".uno:Undo", {});
1907 dispatchCommand(mxComponent, ".uno:Undo", {});
1909 emulateTyping(*pTextDoc, u"et ");
1910 // This was "Ttest" removing the tracked deletion silently.
1911 // Don't replace, if a redline starts or ends within the text.
1912 sReplaced = "tset ";
1913 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1915 // Otherwise replace it
1916 emulateTyping(*pTextDoc, u"tset ");
1917 sReplaced = "tset test ";
1918 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1920 // Including capitalization
1921 emulateTyping(*pTextDoc, u"end. word ");
1922 sReplaced = "tset test end. Word ";
1923 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1925 // tracked deletions after the correction point doesn't affect autocorrect
1926 dispatchCommand(mxComponent, ".uno:GoToStartOfDoc", {});
1927 emulateTyping(*pTextDoc, u"a ");
1928 sReplaced = "A tset test end. Word ";
1929 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1932 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testRedlineAutoCorrect2)
1934 createSwDoc("redline-autocorrect2.fodt");
1935 SwDoc* pDoc = getSwDoc();
1936 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1937 CPPUNIT_ASSERT(pWrtShell);
1938 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1940 dispatchCommand(mxComponent, ".uno:GoToEndOfDoc", {});
1942 // show tracked deletion
1943 RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
1944 CPPUNIT_ASSERT(nMode & (RedlineFlags::ShowDelete | RedlineFlags::ShowInsert));
1945 pWrtShell->SetRedlineFlags(nMode);
1946 CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);
1948 emulateTyping(*pTextDoc, u"... ");
1950 // This was "LoremLorem,…," (duplicating the deleted comma, but without deletion)
1951 // Don't replace, if a redline starts or ends within the text.
1952 OUString sReplaced = "Lorem,... ";
1953 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1955 // Continue it:
1956 emulateTyping(*pTextDoc, u"Lorem,... ");
1957 sReplaced = u"Lorem,... Lorem,… ";
1958 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1961 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testEmojiAutoCorrect)
1963 createSwDoc("redline-autocorrect3.fodt");
1964 SwDoc* pDoc = getSwDoc();
1965 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1966 CPPUNIT_ASSERT(pWrtShell);
1967 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1969 // Emoji replacement (:snowman: -> ☃)
1971 // without change tracking
1972 CPPUNIT_ASSERT(!(pWrtShell->GetRedlineFlags() & RedlineFlags::On));
1973 emulateTyping(*pTextDoc, u":snowman:");
1974 OUString sReplaced = u"☃Lorem,";
1975 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1977 // with change tracking (showing redlines)
1978 RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
1979 CPPUNIT_ASSERT(nMode & (RedlineFlags::ShowDelete | RedlineFlags::ShowInsert));
1980 pWrtShell->SetRedlineFlags(nMode);
1981 CPPUNIT_ASSERT(nMode & RedlineFlags::On);
1982 CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);
1984 emulateTyping(*pTextDoc, u":snowman:");
1985 sReplaced = u"☃☃Lorem,";
1987 // tdf#140674 This was ":snowman:" instead of autocorrect
1988 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
1991 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf108423)
1993 createSwDoc();
1994 SwDoc* pDoc = getSwDoc();
1995 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
1996 CPPUNIT_ASSERT(pWrtShell);
1997 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
1998 // testing autocorrect of i' -> I' on start of first paragraph
1999 emulateTyping(*pTextDoc, u"i'");
2000 // The word "i" should be capitalized due to autocorrect, followed by a typographical apostrophe
2001 OUString sIApostrophe(u"I\u2019");
2002 CPPUNIT_ASSERT_EQUAL(sIApostrophe, getParagraph(1)->getString());
2003 emulateTyping(*pTextDoc, u" i'");
2004 OUString sText(sIApostrophe + u" " + sIApostrophe);
2005 CPPUNIT_ASSERT_EQUAL(sText, getParagraph(1)->getString());
2008 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf153423)
2010 createSwDoc();
2011 SvxSwAutoFormatFlags flags(*SwEditShell::GetAutoFormatFlags());
2012 comphelper::ScopeGuard const g([=]() { SwEditShell::SetAutoFormatFlags(&flags); });
2013 flags.bSetNumRule = true;
2014 SwEditShell::SetAutoFormatFlags(&flags);
2016 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2017 emulateTyping(*pTextDoc, u"1. Item 1");
2019 SwXTextDocument* pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2020 CPPUNIT_ASSERT(pXTextDocument);
2021 pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RETURN);
2022 pXTextDocument->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_RETURN);
2023 Scheduler::ProcessEventsToIdle();
2025 // Without the fix in place, this test would have failed with
2026 // - Expected: 1.
2027 // - Actual : 10.
2028 CPPUNIT_ASSERT_EQUAL(OUString("1."), getProperty<OUString>(getParagraph(1), "ListLabelString"));
2031 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf106164)
2033 createSwDoc();
2034 SwDoc* pDoc = getSwDoc();
2035 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2036 CPPUNIT_ASSERT(pWrtShell);
2037 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2038 // testing autocorrect of we're -> We're on start of first paragraph
2039 emulateTyping(*pTextDoc, u"we're ");
2040 CPPUNIT_ASSERT_EQUAL(OUString(u"We\u2019re "), getParagraph(1)->getString());
2043 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf54409)
2045 createSwDoc();
2046 SwDoc* pDoc = getSwDoc();
2047 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2048 CPPUNIT_ASSERT(pWrtShell);
2049 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2050 // testing autocorrect of "tset -> "test with typographical double quotation mark U+201C
2051 emulateTyping(*pTextDoc, u"\"test ");
2052 OUString sReplaced(u"\u201Ctest ");
2053 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2054 // testing autocorrect of test" -> test" with typographical double quotation mark U+201D
2055 emulateTyping(*pTextDoc, u"and tset\" ");
2056 OUString sReplaced2(sReplaced + u"and test\u201D ");
2057 CPPUNIT_ASSERT_EQUAL(sReplaced2, getParagraph(1)->getString());
2058 // testing autocorrect of "tset" -> "test" with typographical double quotation mark U+201C and U+201D
2059 emulateTyping(*pTextDoc, u"\"tset\" ");
2060 OUString sReplaced3(sReplaced2 + u"\u201Ctest\u201D ");
2061 CPPUNIT_ASSERT_EQUAL(sReplaced3, getParagraph(1)->getString());
2064 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf38394)
2066 createSwDoc("tdf38394.fodt");
2067 SwDoc* pDoc = getSwDoc();
2068 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2069 CPPUNIT_ASSERT(pWrtShell);
2070 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2071 // testing autocorrect of French l'" -> l'« (instead of l'»)
2072 emulateTyping(*pTextDoc, u"l'\"");
2073 OUString sReplaced(u"l\u2019« ");
2074 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2075 // tdf#132301 autocorrect of qu'«
2076 emulateTyping(*pTextDoc, u" qu'\"");
2077 sReplaced += u" qu\u2019« ";
2078 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2081 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf59666)
2083 createSwDoc();
2084 SwDoc* pDoc = getSwDoc();
2085 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2086 CPPUNIT_ASSERT(pWrtShell);
2087 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2088 // testing missing autocorrect of single Greek letters
2089 emulateTyping(*pTextDoc, u"π ");
2090 CPPUNIT_ASSERT_EQUAL(OUString(u"\u03C0 "), getParagraph(1)->getString());
2093 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf133524)
2095 createSwDoc("tdf133524.fodt");
2096 SwDoc* pDoc = getSwDoc();
2097 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2098 CPPUNIT_ASSERT(pWrtShell);
2099 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2100 // 1. Testing autocorrect of >> and <<
2101 // Example: »word«
2102 emulateTyping(*pTextDoc, u">>");
2103 OUString sReplaced(u"»");
2104 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2105 // <<
2106 emulateTyping(*pTextDoc, u"word<<");
2107 sReplaced += u"word«";
2108 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2109 // 2. Testing autocorrect of " to >> and << inside „...”
2110 // Example: „Sentence and »word«.”
2111 // opening primary level quote
2112 emulateTyping(*pTextDoc, u" \"");
2113 sReplaced += u" „";
2114 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2115 // opening second level quote
2116 emulateTyping(*pTextDoc, u"Sentence and \"");
2117 sReplaced += u"Sentence and »";
2118 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2119 // closing second level quote
2120 emulateTyping(*pTextDoc, u"word\"");
2121 sReplaced += u"word«";
2122 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2123 // closing primary level quote
2124 emulateTyping(*pTextDoc, u".\"");
2125 sReplaced += u".”";
2126 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2127 // tdf#134940 avoid premature replacement of "--" in "-->"
2128 emulateTyping(*pTextDoc, u" -->");
2129 OUString sReplaced2(sReplaced + u" -->");
2130 // This was "–>" instead of "-->"
2131 CPPUNIT_ASSERT_EQUAL(sReplaced2, getParagraph(1)->getString());
2132 emulateTyping(*pTextDoc, u" ");
2133 sReplaced += u" → ";
2134 // This was "–>" instead of "→"
2135 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2137 // tdf#83037
2138 emulateTyping(*pTextDoc, u"-> ");
2139 sReplaced += u"→ ";
2140 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2141 emulateTyping(*pTextDoc, u"<- ");
2142 sReplaced += u"← ";
2143 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2144 emulateTyping(*pTextDoc, u"<-- ");
2145 sReplaced += u"← ";
2146 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2147 emulateTyping(*pTextDoc, u"<--> ");
2148 sReplaced += u"↔ ";
2149 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2152 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf133524_Romanian)
2154 createSwDoc("tdf133524_ro.fodt");
2155 SwDoc* pDoc = getSwDoc();
2156 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2157 CPPUNIT_ASSERT(pWrtShell);
2158 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2159 // 1. Testing autocorrect of " to << and >> inside „...”
2160 // Example: „Sentence and «word».”
2161 // opening primary level quote
2162 emulateTyping(*pTextDoc, u"\"");
2163 OUString sReplaced(u"„");
2164 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2165 // opening second level quote
2166 emulateTyping(*pTextDoc, u"Sentence and \"");
2167 sReplaced += u"Sentence and «";
2168 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2169 // closing second level quote
2170 emulateTyping(*pTextDoc, u"word\"");
2171 sReplaced += u"word»";
2172 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2173 // closing primary level quote
2174 emulateTyping(*pTextDoc, u".\"");
2175 sReplaced += u".”";
2176 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2177 // 2. Testing recognition of closing double quotation mark ”
2178 emulateTyping(*pTextDoc, u" \"");
2179 sReplaced += u" „";
2180 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2181 // 3. Testing recognition of alternative closing double quotation mark “
2182 emulateTyping(*pTextDoc, u"Alternative.“ \"");
2183 sReplaced += u"Alternative.“ „";
2184 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2187 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf128860)
2189 createSwDoc("tdf128860.fodt");
2190 SwDoc* pDoc = getSwDoc();
2191 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2192 CPPUNIT_ASSERT(pWrtShell);
2193 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2194 // Second level ending quote: ‚word' -> ,word‘
2195 emulateTyping(*pTextDoc, u",word'");
2196 OUString sReplaced(u",word\u2019");
2197 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2198 // Us apostrophe without preceding starting quote: word' -> word’
2199 emulateTyping(*pTextDoc, u" word'");
2200 sReplaced += u" word\u2019";
2201 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2202 // But only after letters: word.' -> word.‘
2203 emulateTyping(*pTextDoc, u" word.'");
2204 sReplaced += u" word.‘";
2205 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2208 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf123786)
2210 createSwDoc("tdf123786.fodt");
2211 SwDoc* pDoc = getSwDoc();
2213 // On Windows, it will detect that system input language is en-US (despite "typing" e.g. Cyrillic characters),
2214 // and will change Russian into English (US); in the latter language,
2215 // the replacement from single quote will not become “, but ’.
2216 SvtSysLocaleOptions aOptions;
2217 aOptions.SetIgnoreLanguageChange(true);
2218 aOptions.Commit();
2220 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2221 CPPUNIT_ASSERT(pWrtShell);
2222 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2223 // Second level ending quote: „word' -> „word“
2224 emulateTyping(*pTextDoc, u"„слово'");
2225 OUString sReplaced(u"„слово“");
2226 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2227 // Us apostrophe without preceding starting quote: word' -> word’
2228 emulateTyping(*pTextDoc, u" слово'");
2229 sReplaced += u" слово’";
2230 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2231 // But only after letters: word.' -> word.“
2232 emulateTyping(*pTextDoc, u" слово.'");
2233 sReplaced += u" слово.“";
2234 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2237 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf133589)
2239 // Hungarian test document with right-to-left paragraph setting
2240 createSwDoc("tdf133589.fodt");
2241 SwDoc* pDoc = getSwDoc();
2242 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2243 CPPUNIT_ASSERT(pWrtShell);
2244 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2245 // translitere words to Old Hungarian
2246 emulateTyping(*pTextDoc, u"székely ");
2247 OUString sReplaced(u"𐳥𐳋𐳓𐳉𐳗 ");
2248 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2249 // disambiguate consonants: asszony -> asz|szony
2250 emulateTyping(*pTextDoc, u"asszony ");
2251 sReplaced += u"𐳀𐳥𐳥𐳛𐳚 ";
2252 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2253 // disambiguate consonants: kosszarv -> kos|szarv
2254 // (add explicit ZWSP temporarily for consonant disambiguation, because the requested
2255 // hu_HU hyphenation dictionary isn't installed on all testing platform)
2256 // pWrtShell->Insert(u"kosszarv");
2257 emulateTyping(*pTextDoc, u"kos\u200Bszarv ");
2258 sReplaced += u"𐳓𐳛𐳤𐳥𐳀𐳢𐳮 ";
2259 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2260 // transliterate numbers to Old Hungarian
2261 emulateTyping(*pTextDoc, u"2020 ");
2262 sReplaced += u"𐳺𐳺𐳿𐳼𐳼 ";
2263 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2265 // tdf#147546 transliterate punctuation marks
2267 // question mark
2268 emulateTyping(*pTextDoc, u"Kérdőjel?");
2269 sReplaced += u"𐲓𐳋𐳢𐳇𐳟𐳒𐳉𐳖";
2270 OUString sReplaced2(sReplaced + "?");
2271 CPPUNIT_ASSERT_EQUAL(sReplaced2, getParagraph(1)->getString());
2272 emulateTyping(*pTextDoc, u" ");
2273 sReplaced += u"⸮ ";
2274 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2275 // comma
2276 emulateTyping(*pTextDoc, u"Vessző,");
2277 sReplaced += u"𐲮𐳉𐳥𐳥𐳟";
2278 sReplaced2 = sReplaced + ",";
2279 CPPUNIT_ASSERT_EQUAL(sReplaced2, getParagraph(1)->getString());
2280 emulateTyping(*pTextDoc, u" ");
2281 sReplaced += u"⹁ ";
2282 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2283 // semicolon
2284 emulateTyping(*pTextDoc, u"pontosvessző;");
2285 sReplaced += u"𐳠𐳛𐳙𐳦𐳛𐳤𐳮𐳉𐳥𐳥𐳟";
2286 sReplaced2 = sReplaced + ";";
2287 CPPUNIT_ASSERT_EQUAL(sReplaced2, getParagraph(1)->getString());
2288 emulateTyping(*pTextDoc, u" ");
2289 sReplaced += u"⁏ ";
2290 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2291 // quotation marks
2292 emulateTyping(*pTextDoc, u"„idézőjel” ");
2293 sReplaced += u"⹂𐳐𐳇𐳋𐳯𐳟𐳒𐳉𐳖‟ ";
2294 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2296 // tdf#148672 transliterate word with closing bracket
2297 emulateTyping(*pTextDoc, u"word] ");
2298 sReplaced += u"𐳮𐳛𐳢𐳇] "; // This was "word]" (no transliteration)
2299 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2301 // tdf#148672 transliterate words with parenthesis (libnumbertext 1.0.11)
2302 emulateTyping(*pTextDoc, u"(word) ");
2303 sReplaced += u"(𐳮𐳛𐳢𐳇) "; // This was "(word)" (no transliteration)
2304 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2306 emulateTyping(*pTextDoc, u"(word ");
2307 sReplaced += u"(𐳮𐳛𐳢𐳇 "; // This was "(word" (no transliteration)
2308 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2310 emulateTyping(*pTextDoc, u"word) ");
2311 sReplaced += u"𐳮𐳛𐳢𐳇) "; // This was "word)" (no transliteration)
2312 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2314 emulateTyping(*pTextDoc, u"{word} ");
2315 sReplaced += u"{𐳮𐳛𐳢𐳇} "; // This was "(word)" (no transliteration)
2316 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2318 emulateTyping(*pTextDoc, u"{word ");
2319 sReplaced += u"{𐳮𐳛𐳢𐳇 "; // This was "(word" (no transliteration)
2320 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2322 emulateTyping(*pTextDoc, u"word} ");
2323 sReplaced += u"𐳮𐳛𐳢𐳇} "; // This was "word)" (no transliteration)
2324 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2326 emulateTyping(*pTextDoc, u"[word] ");
2327 sReplaced += u"[𐳮𐳛𐳢𐳇] "; // This was "(word)" (no transliteration)
2328 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2330 emulateTyping(*pTextDoc, u"[word ");
2331 sReplaced += u"[𐳮𐳛𐳢𐳇 "; // This was "(word" (no transliteration)
2332 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2335 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testAutoCorr)
2337 createSwDoc();
2338 SwDoc* pDoc = getSwDoc();
2339 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2340 CPPUNIT_ASSERT(pWrtShell);
2341 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2343 //Normal AutoCorrect
2344 emulateTyping(*pTextDoc, u"tset ");
2345 CPPUNIT_ASSERT_EQUAL(OUString("Test "), getParagraph(1)->getString());
2347 //AutoCorrect with change style to bolt
2348 emulateTyping(*pTextDoc, u"Bolt ");
2349 const uno::Reference<text::XTextRange> xRun = getRun(getParagraph(1), 2);
2350 CPPUNIT_ASSERT_EQUAL(OUString("Bolt"), xRun->getString());
2351 CPPUNIT_ASSERT_EQUAL(OUString("Arial"), getProperty<OUString>(xRun, "CharFontName"));
2353 //AutoCorrect inserts Table with 2 rows and 3 columns
2354 emulateTyping(*pTextDoc, u"4xx ");
2355 const uno::Reference<text::XTextTable> xTable(getParagraphOrTable(2), uno::UNO_QUERY);
2356 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable->getRows()->getCount());
2357 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable->getColumns()->getCount());
2360 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf130274)
2362 createSwDoc();
2363 SwDoc* pDoc = getSwDoc();
2364 SwWrtShell* const pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2365 CPPUNIT_ASSERT(pWrtShell);
2366 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2368 CPPUNIT_ASSERT(!pWrtShell->GetLayout()->IsHideRedlines());
2369 CPPUNIT_ASSERT(
2370 !IDocumentRedlineAccess::IsRedlineOn(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
2372 // "tset" may be replaced by the AutoCorrect in the test profile
2373 emulateTyping(*pTextDoc, u"tset");
2374 // select from left to right
2375 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 4, /*bBasicCall=*/false);
2376 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 4, /*bBasicCall=*/false);
2378 pWrtShell->SetRedlineFlags(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
2379 // this would crash in AutoCorrect
2380 emulateTyping(*pTextDoc, u".");
2382 CPPUNIT_ASSERT(!pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty());
2385 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf83260)
2387 createSwDoc("tdf83260-1.odt");
2388 SwDoc* pDoc = getSwDoc();
2389 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2390 CPPUNIT_ASSERT(pWrtShell);
2391 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2393 // enabled but not shown
2394 CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());
2395 #if 0
2396 CPPUNIT_ASSERT(IDocumentRedlineAccess::IsHideChanges(
2397 pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
2398 #endif
2399 CPPUNIT_ASSERT(
2400 IDocumentRedlineAccess::IsRedlineOn(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
2401 CPPUNIT_ASSERT(!pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty());
2403 // the document contains redlines that are combined with CompressRedlines()
2404 // if that happens during AutoCorrect then indexes in Undo are off -> crash
2405 emulateTyping(*pTextDoc, u"tset ");
2406 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
2407 auto const nActions(rUndoManager.GetUndoActionCount());
2408 for (auto i = nActions; 0 < i; --i)
2410 rUndoManager.Undo();
2412 // check that every text node has a layout frame
2413 for (SwNodeOffset i(0); i < pDoc->GetNodes().Count(); ++i)
2415 if (SwTextNode const* const pNode = pDoc->GetNodes()[i]->GetTextNode())
2417 CPPUNIT_ASSERT(pNode->getLayoutFrame(nullptr, nullptr, nullptr));
2420 for (auto i = nActions; 0 < i; --i)
2422 rUndoManager.Redo();
2424 for (SwNodeOffset i(0); i < pDoc->GetNodes().Count(); ++i)
2426 if (SwTextNode const* const pNode = pDoc->GetNodes()[i]->GetTextNode())
2428 CPPUNIT_ASSERT(pNode->getLayoutFrame(nullptr, nullptr, nullptr));
2431 for (auto i = nActions; 0 < i; --i)
2433 rUndoManager.Undo();
2435 for (SwNodeOffset i(0); i < pDoc->GetNodes().Count(); ++i)
2437 if (SwTextNode const* const pNode = pDoc->GetNodes()[i]->GetTextNode())
2439 CPPUNIT_ASSERT(pNode->getLayoutFrame(nullptr, nullptr, nullptr));
2444 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf74363)
2446 createSwDoc();
2447 SwDoc* pDoc = getSwDoc();
2448 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2449 CPPUNIT_ASSERT(pWrtShell);
2450 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2451 //testing autocorrect of initial capitals on start of first paragraph
2452 //Inserting one all-lowercase word into the first paragraph
2453 emulateTyping(*pTextDoc, u"testing ");
2454 //The word should be capitalized due to autocorrect
2455 CPPUNIT_ASSERT_EQUAL(OUString("Testing "), getParagraph(1)->getString());
2458 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf139922)
2460 createSwDoc();
2461 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2463 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RETURN);
2464 Scheduler::ProcessEventsToIdle();
2466 emulateTyping(*pTextDoc, u"this is a SEntence. this is a SEntence.");
2468 // Without the fix in place, this test would have failed with
2469 // - Expected: This is a Sentence. This is a Sentence.
2470 // - Actual : this is a Sentence. This is a Sentence.
2471 CPPUNIT_ASSERT_EQUAL(OUString("This is a Sentence. This is a Sentence."),
2472 getParagraph(2)->getString());
2475 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf143176)
2477 // Hungarian test document with right-to-left paragraph setting
2478 createSwDoc("tdf143176.fodt");
2480 // transliterate the document to Old Hungarian (note: it only works
2481 // with right-to-left text direction and Default Paragraph Style)
2482 dispatchCommand(mxComponent, ".uno:AutoFormatApply", {});
2484 // This was the original "Lorem ipsum..."
2485 CPPUNIT_ASSERT_EQUAL(OUString(u"𐲖𐳛𐳢𐳉𐳘 𐳐𐳠𐳤𐳪𐳘 𐳇𐳛𐳖𐳛𐳢 "
2486 u"𐳤𐳐𐳦 𐳀𐳘𐳉𐳦⹁"),
2487 getParagraph(1)->getString());
2488 CPPUNIT_ASSERT_EQUAL(OUString(u"𐳄𐳛𐳙𐳤𐳉𐳄𐳦𐳉𐳦𐳪𐳢 "
2489 u"𐳀𐳇𐳐𐳠𐳐𐳤𐳄𐳐𐳙𐳍 𐳉𐳖𐳐𐳦."),
2490 getParagraph(2)->getString());
2493 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testInsertLongDateFormat)
2495 // only for Hungarian, yet
2496 createSwDoc("tdf133524.fodt");
2497 dispatchCommand(mxComponent, ".uno:InsertDateField", {});
2498 // Make sure that the document starts with a field now, and its expanded string value contains space
2499 const uno::Reference<text::XTextRange> xField = getRun(getParagraph(1), 1);
2500 CPPUNIT_ASSERT_EQUAL(OUString("TextField"), getProperty<OUString>(xField, "TextPortionType"));
2501 // the date format was "YYYY-MM-DD", but now "YYYY. MMM DD."
2502 CPPUNIT_ASSERT(xField->getString().indexOf(" ") > -1);
2505 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf129270)
2507 createSwDoc("tdf129270.odt");
2508 SwDoc* pDoc = getSwDoc();
2509 CPPUNIT_ASSERT(pDoc);
2510 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2511 CPPUNIT_ASSERT(pWrtShell);
2512 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2514 // Go to document end
2515 pWrtShell->SttEndDoc(/*bStt=*/false);
2517 // Press enter
2518 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RETURN);
2519 Scheduler::ProcessEventsToIdle();
2521 // Numbering for previous outline should remain the same "2"
2522 CPPUNIT_ASSERT_EQUAL(OUString("2"), getProperty<OUString>(getParagraph(4), "ListLabelString"));
2524 // Numbering for newly created outline should be "2.1"
2525 CPPUNIT_ASSERT_EQUAL(OUString("2.1"),
2526 getProperty<OUString>(getParagraph(5), "ListLabelString"));
2529 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testInsertPdf)
2531 auto pPdfium = vcl::pdf::PDFiumLibrary::get();
2532 if (!pPdfium)
2534 return;
2537 createSwDoc();
2539 // insert the PDF into the document
2540 uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
2541 { { "FileName", uno::Any(createFileURL(u"hello-world.pdf")) } }));
2542 dispatchCommand(mxComponent, ".uno:InsertGraphic", aArgs);
2544 // Save and load cycle
2545 saveAndReload("writer8");
2547 uno::Reference<drawing::XShape> xShape = getShape(1);
2548 // Assert that we have a replacement graphics
2549 auto xReplacementGraphic
2550 = getProperty<uno::Reference<graphic::XGraphic>>(xShape, "ReplacementGraphic");
2551 CPPUNIT_ASSERT(xReplacementGraphic.is());
2553 auto xGraphic = getProperty<uno::Reference<graphic::XGraphic>>(xShape, "Graphic");
2554 CPPUNIT_ASSERT(xGraphic.is());
2555 // Assert that the graphic is a PDF
2556 CPPUNIT_ASSERT_EQUAL(OUString("application/pdf"), getProperty<OUString>(xGraphic, "MimeType"));
2559 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf143760WrapContourToOff)
2561 // Actually, this is an ooxmlexport test. It is here because here is a ready environment
2562 // to change a shape by dispatchCommand.
2563 createSwDoc("tdf143760_ContourToWrapOff.docx");
2564 SwDoc* pDoc = getSwDoc();
2565 CPPUNIT_ASSERT(pDoc);
2566 CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(getShape(1), "SurroundContour"));
2568 // Mark the object
2569 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2570 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
2571 SdrObject* pObject = pPage->GetObj(0);
2572 CPPUNIT_ASSERT(pObject);
2573 SdrView* pView = pWrtShell->GetDrawView();
2574 pView->MarkObj(pObject, pView->GetSdrPageView());
2576 // Set "wrap off"
2577 dispatchCommand(mxComponent, ".uno:WrapOff", {});
2578 CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(getShape(1), "SurroundContour"));
2580 // Without fix this had failed, because the shape was written to file with contour.
2581 saveAndReload("Office Open XML Text");
2582 CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(getShape(1), "SurroundContour"));
2585 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testHatchFill)
2587 createSwDoc();
2589 // Add a rectangle shape to the document.
2590 uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
2591 uno::Reference<drawing::XShape> xShape(
2592 xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY);
2593 xShape->setSize(awt::Size(10000, 10000));
2594 xShape->setPosition(awt::Point(1000, 1000));
2595 uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
2596 xShapeProps->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_HATCH));
2597 xShapeProps->setPropertyValue("FillHatchName", uno::Any(OUString("Black 0 Degrees")));
2598 xShapeProps->setPropertyValue("FillBackground", uno::Any(false));
2599 xShapeProps->setPropertyValue("FillTransparence", uno::Any(sal_Int32(30)));
2600 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
2601 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
2602 xDrawPage->add(xShape);
2604 // Save it as DOCX and load it again.
2605 saveAndReload("Office Open XML Text");
2606 CPPUNIT_ASSERT_EQUAL(1, getShapes());
2608 // tdf#127989 Without fix this had failed, because the background of the hatch was not set as 'no background'.
2609 CPPUNIT_ASSERT(!getProperty<bool>(getShape(1), "FillBackground"));
2611 // tdf#146822 Without fix this had failed, because the transparency value of the hatch was not exported.
2612 CPPUNIT_ASSERT_EQUAL(sal_Int32(30), getProperty<sal_Int32>(getShape(1), "FillTransparence"));
2615 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testNestedGroupTextBoxCopyCrash)
2617 createSwDoc("tdf149550.docx");
2619 dispatchCommand(mxComponent, ".uno:SelectAll", {});
2620 dispatchCommand(mxComponent, ".uno:Copy", {});
2621 // This crashed here before the fix.
2622 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
2623 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_ESCAPE);
2624 Scheduler::ProcessEventsToIdle();
2625 dispatchCommand(mxComponent, ".uno:Paste", {});
2627 CPPUNIT_ASSERT_MESSAGE("Where is the doc, it crashed, isn't it?!", mxComponent);
2629 auto pLayout = parseLayoutDump();
2630 // There must be 2 textboxes!
2631 assertXPath(pLayout, "/root/page/body/txt/anchored/fly[2]");
2634 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testCrashOnExit)
2636 // Load the bugdoc with a table and a textbox shape inside.
2637 createSwDoc("tdf142715.odt");
2639 // Get the textbox selected
2640 CPPUNIT_ASSERT_EQUAL(1, getShapes());
2642 selectShape(1);
2643 auto xShape = getShape(1);
2644 uno::Reference<beans::XPropertySet> xProperties(xShape, uno::UNO_QUERY);
2646 // Check if the textbox is selected
2647 CPPUNIT_ASSERT_EQUAL(true, xProperties->getPropertyValue("TextBox").get<bool>());
2649 // Remove the textbox
2650 dispatchCommand(mxComponent, ".uno:RemoveTextBox", {});
2652 CPPUNIT_ASSERT_EQUAL(false, xProperties->getPropertyValue("TextBox").get<bool>());
2654 // Readd the textbox (to run the textboxhelper::create() method)
2655 dispatchCommand(mxComponent, ".uno:AddTextBox", {});
2657 CPPUNIT_ASSERT_EQUAL(true, xProperties->getPropertyValue("TextBox").get<bool>());
2659 // save and reload
2660 saveAndReload("writer8");
2662 // Before the fix this crashed here and could not reopen.
2663 CPPUNIT_ASSERT_MESSAGE("Crash on exit, isn't it?", mxComponent);
2666 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testCaptionShape)
2668 createSwDoc();
2670 // Add a caption shape to the document.
2671 uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
2672 uno::Reference<drawing::XShape> xShape(
2673 xFactory->createInstance("com.sun.star.drawing.CaptionShape"), uno::UNO_QUERY);
2674 xShape->setSize(awt::Size(10000, 10000));
2675 xShape->setPosition(awt::Point(1000, 1000));
2676 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
2677 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
2678 xDrawPage->add(xShape);
2680 // Save it as DOCX and load it again.
2681 saveAndReload("Office Open XML Text");
2683 // Without fix in place, the shape was lost on export.
2684 CPPUNIT_ASSERT_EQUAL(1, getShapes());
2687 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf151828_Comment2)
2689 createSwDoc();
2691 // Add a basic shape to the document.
2692 uno::Sequence<beans::PropertyValue> aArgs(
2693 comphelper::InitPropertySequence({ { "KeyModifier", uno::Any(KEY_MOD1) } }));
2694 dispatchCommand(mxComponent, ".uno:BasicShapes", aArgs);
2696 auto xBasicShape = getShape(1);
2697 auto pObject = SdrObject::getSdrObjectFromXShape(xBasicShape);
2699 CPPUNIT_ASSERT_EQUAL(1, getShapes());
2701 // rename the shape name
2702 pObject->SetName("Shape");
2704 // cut and paste it
2705 dispatchCommand(mxComponent, ".uno:Cut", {});
2707 CPPUNIT_ASSERT_EQUAL(0, getShapes());
2709 dispatchCommand(mxComponent, ".uno:Paste", {});
2711 CPPUNIT_ASSERT_EQUAL(1, getShapes());
2713 // it is required to get the shape object again after paste
2714 xBasicShape = getShape(1);
2715 pObject = SdrObject::getSdrObjectFromXShape(xBasicShape);
2717 // Without fix in place, the shape name was 'Shape 1' after paste.
2718 CPPUNIT_ASSERT_EQUAL(OUString("Shape"), pObject->GetName());
2721 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf151828)
2723 createSwDoc();
2724 SwDoc* pDoc = getSwDoc();
2725 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2727 // insert a table
2728 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
2729 pWrtShell->InsertTable(TableOpt, 1, 1);
2731 // move cursor into the table
2732 CPPUNIT_ASSERT(pWrtShell->MoveTable(GotoPrevTable, fnTableStart));
2734 SwFrameFormat* pFormat = pWrtShell->GetTableFormat();
2735 CPPUNIT_ASSERT(pFormat);
2737 // set name of table to 'MyTableName'
2738 pWrtShell->SetTableName(*pFormat, "MyTableName");
2740 // cut and paste the table
2741 dispatchCommand(mxComponent, ".uno:SelectTable", {});
2742 dispatchCommand(mxComponent, ".uno:Cut", {});
2743 dispatchCommand(mxComponent, ".uno:Paste", {});
2745 // move cursor into the pasted table
2746 CPPUNIT_ASSERT(pWrtShell->MoveTable(GotoPrevTable, fnTableStart));
2748 pFormat = pWrtShell->GetTableFormat();
2749 CPPUNIT_ASSERT(pFormat);
2751 // Before the fix the pasted table name was 'Table1'.
2752 CPPUNIT_ASSERT_EQUAL(OUString("MyTableName"), pFormat->GetName());
2755 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf146178)
2757 createSwDoc();
2759 SwDoc* pDoc = getSwDoc();
2760 SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
2761 SwPaM* pCursor = pDoc->GetEditShell()->GetCursor();
2763 // insert two fields
2764 dispatchCommand(mxComponent, ".uno:InsertTimeField", {});
2765 dispatchCommand(mxComponent, ".uno:InsertDateField", {});
2767 // navigate by field
2768 SwView::SetMoveType(NID_FIELD);
2770 // set cursor to the start of the document
2771 pWrtShell->SttEndDoc(false);
2772 // navigate to the previous field
2773 dispatchCommand(mxComponent, ".uno:ScrollToPrevious", {});
2774 // Before the fix the position would be 0, navigation did not wrap to end of document
2775 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pCursor->GetPoint()->GetContentIndex());
2777 // set cursor to the end of the document
2778 pWrtShell->SttEndDoc(false);
2779 // navigate to the next field
2780 dispatchCommand(mxComponent, ".uno:ScrollToNext", {});
2781 // Before the fix the position would be 1, navigation did not wrap to start of document
2782 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pCursor->GetPoint()->GetContentIndex());
2785 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf155407)
2787 createSwDoc();
2788 SwXTextDocument& rTextDoc = dynamic_cast<SwXTextDocument&>(*mxComponent);
2791 emulateTyping(rTextDoc, u"Foo - 11’--’22 ");
2792 // Without the fix in place, this would fail with
2793 // - Expected: Foo – 11’—’22
2794 // - Actual : Foo – 11’--’22
2795 CPPUNIT_ASSERT_EQUAL(OUString(u"Foo – 11’—’22 "), getParagraph(1)->getString());
2798 dispatchCommand(mxComponent, ".uno:SelectAll", {}); // start again
2801 emulateTyping(rTextDoc, u"Bar -- 111--222 ");
2802 // Without the fix in place, this would fail with
2803 // - Expected: Bar – 111–222
2804 // - Actual : Bar – 111-–22
2805 CPPUNIT_ASSERT_EQUAL(OUString(u"Bar – 111–222 "), getParagraph(1)->getString());
2809 CPPUNIT_PLUGIN_IMPLEMENT();
2811 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */