tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / sw / qa / extras / uiwriter / uiwriter6.cxx
blobaf5c132f880a21754db4218dec75c192da55d84a
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 <edtwin.hxx>
17 #include <drawdoc.hxx>
18 #include <view.hxx>
19 #include <com/sun/star/text/XTextColumns.hpp>
21 #include <svx/svdpage.hxx>
22 #include <svx/svdview.hxx>
23 #include <svl/itemiter.hxx>
24 #include <vcl/filter/PDFiumLibrary.hxx>
26 #include <dbfld.hxx>
27 #include <txatbase.hxx>
28 #include <IDocumentDrawModelAccess.hxx>
29 #include <IDocumentRedlineAccess.hxx>
30 #include <IDocumentLayoutAccess.hxx>
31 #include <UndoManager.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 <tools/UnitConversion.hxx>
39 #include <boost/property_tree/json_parser.hpp>
41 #include <com/sun/star/text/XTextTable.hpp>
42 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
43 #include <com/sun/star/view/XSelectionSupplier.hpp>
44 #include <o3tl/cppunittraitshelper.hxx>
45 #include <swdtflvr.hxx>
46 #include <comphelper/propertysequence.hxx>
47 #include <comphelper/processfactory.hxx>
48 #include <comphelper/sequence.hxx>
49 #include <comphelper/scopeguard.hxx>
50 #include <editeng/swafopt.hxx>
51 #include <editeng/unolingu.hxx>
52 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
53 #include <vcl/scheduler.hxx>
54 #include <config_fonts.h>
55 #include <test/htmltesttools.hxx>
56 #include <wrthtml.hxx>
57 #include <dbmgr.hxx>
58 #include <rootfrm.hxx>
59 #include <pagefrm.hxx>
60 #include <sortedobjs.hxx>
61 #include <flyfrms.hxx>
62 #include <tabfrm.hxx>
63 #include <unotxdoc.hxx>
64 #include <wrong.hxx>
65 #include <com/sun/star/linguistic2/LinguServiceManager.hpp>
66 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
67 #include <com/sun/star/linguistic2/XSpellChecker1.hpp>
68 #include <linguistic/misc.hxx>
70 #include <workctrl.hxx>
72 using namespace com::sun::star;
73 using namespace com::sun::star::beans;
74 using namespace com::sun::star::lang;
75 using namespace com::sun::star::uno;
76 using namespace com::sun::star::linguistic2;
77 using namespace linguistic;
79 namespace
81 sal_Int32 lcl_getAttributeIDFromHints(const SwpHints& hints)
83 for (size_t i = 0; i < hints.Count(); ++i)
85 const SwTextAttr* hint = hints.Get(i);
86 if (hint->Which() == RES_TXTATR_AUTOFMT)
88 const SwFormatAutoFormat& rFmt = hint->GetAutoFormat();
89 SfxItemIter aIter(*rFmt.GetStyleHandle());
90 return aIter.GetCurItem()->Which();
93 return -1;
96 uno::Reference<XLinguServiceManager2> GetLngSvcMgr_Impl()
98 uno::Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
99 uno::Reference<XLinguServiceManager2> xRes = LinguServiceManager::create(xContext);
100 return xRes;
102 } //namespace
104 class SwUiWriterTest6 : public SwModelTestBase, public HtmlTestTools
106 public:
107 SwUiWriterTest6()
108 : SwModelTestBase(u"/sw/qa/extras/uiwriter/data/"_ustr)
113 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf116640)
115 createSwDoc();
117 uno::Sequence<beans::PropertyValue> aArgs(
118 comphelper::InitPropertySequence({ { "Columns", uno::Any(sal_Int32(2)) } }));
120 dispatchCommand(mxComponent, u".uno:InsertSection"_ustr, aArgs);
122 uno::Reference<text::XTextSectionsSupplier> xTextSectionsSupplier(mxComponent, uno::UNO_QUERY);
123 uno::Reference<container::XIndexAccess> xSections(xTextSectionsSupplier->getTextSections(),
124 uno::UNO_QUERY);
125 uno::Reference<beans::XPropertySet> xTextSection(xSections->getByIndex(0), uno::UNO_QUERY);
127 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
129 uno::Reference<text::XTextColumns> xTextColumns
130 = getProperty<uno::Reference<text::XTextColumns>>(xTextSection, u"TextColumns"_ustr);
131 CPPUNIT_ASSERT_EQUAL(sal_Int16(2), xTextColumns->getColumnCount());
133 dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
135 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xSections->getCount());
137 dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});
139 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
141 dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
143 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xSections->getCount());
146 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf108524)
148 createSwDoc("tdf108524.odt");
149 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
150 // In total we expect two cells containing a section.
151 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/section", 2);
153 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell/section", 1);
154 // This was 0, section wasn't split, instead it was only on the first page
155 // and it was cut off.
156 assertXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell/section", 1);
159 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testLinesInSectionInTable)
161 // This is similar to testTdf108524(), but the page boundary now is not in
162 // the middle of a multi-line paragraph: the section only contains oneliner
163 // paragraphs instead.
164 createSwDoc("lines-in-section-in-table.odt");
165 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
166 // In total we expect two cells containing a section.
167 assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/section", 2);
169 assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell/section", 1);
170 // This was 0, section wasn't split, instead it was only on the first page
171 // and it was cut off.
172 assertXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell/section", 1);
175 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testLinesMoveBackwardsInSectionInTable)
177 #if HAVE_MORE_FONTS
178 // Assert that paragraph "4" is on page 1 and "5" is on page 2.
179 createSwDoc("lines-in-section-in-table.odt");
180 SwDoc* pDoc = getSwDoc();
181 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
182 assertXPath(pXmlDoc, "/root/page", 2);
183 SwNodeOffset nPara4Node(
184 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/section/txt[last()]", "txtNodeIndex")
185 .toUInt32());
186 CPPUNIT_ASSERT_EQUAL(u"4"_ustr, pDoc->GetNodes()[nPara4Node]->GetTextNode()->GetText());
187 SwNodeOffset nPara5Node(
188 getXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell[1]/section/txt[1]", "txtNodeIndex")
189 .toUInt32());
190 CPPUNIT_ASSERT_EQUAL(u"5"_ustr, pDoc->GetNodes()[nPara5Node]->GetTextNode()->GetText());
192 // Remove paragraph "4".
193 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
194 while (pWrtShell->GetCursor()->GetPointNode().GetIndex() < nPara4Node)
195 pWrtShell->Down(/*bSelect=*/false);
196 pWrtShell->EndPara();
197 pWrtShell->Up(/*bSelect=*/true);
198 pWrtShell->DelLeft();
200 // Assert that paragraph "5" is now moved back to page 1 and is the last paragraph there.
201 pXmlDoc = parseLayoutDump();
202 SwNodeOffset nPage1LastNode(
203 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/section/txt[last()]", "txtNodeIndex")
204 .toUInt32());
205 // This was "3", paragraph "4" was deleted, but "5" was not moved backwards from page 2.
206 CPPUNIT_ASSERT_EQUAL(u"5"_ustr, pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
207 #endif
210 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTableInSection)
212 #if HAVE_MORE_FONTS
213 // The document has a section, containing a table that spans over 2 pages.
214 createSwDoc("table-in-sect.odt");
215 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
216 // In total we expect 4 cells.
217 assertXPath(pXmlDoc, "/root/page/body/section/tab/row/cell", 4);
219 // Assert that on both pages the section contains 2 cells.
220 assertXPath(pXmlDoc, "/root/page[1]/body/section/tab/row/cell", 2);
221 assertXPath(pXmlDoc, "/root/page[2]/body/section/tab/row/cell", 2);
222 #endif
225 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTableInNestedSection)
227 #if HAVE_MORE_FONTS
228 // The document has a nested section, containing a table that spans over 2 pages.
229 // This crashed the layout.
230 createSwDoc("rhbz739252-3.odt");
231 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
232 // Make sure the table is inside a section and spans over 2 pages.
233 assertXPath(pXmlDoc, "//page[1]//section/tab", 1);
234 assertXPath(pXmlDoc, "//page[2]//section/tab", 1);
235 #endif
238 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112741)
240 #if HAVE_MORE_FONTS
241 createSwDoc("tdf112741.fodt");
242 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
243 // This was 5 pages.
244 assertXPath(pXmlDoc, "//page", 4);
245 assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell/section", 1);
246 assertXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row/cell/section", 1);
247 // This failed, 3rd page contained no sections.
248 assertXPath(pXmlDoc, "//page[3]/body/tab/row/cell/tab/row/cell/section", 1);
249 assertXPath(pXmlDoc, "//page[4]/body/tab/row/cell/tab/row/cell/section", 1);
250 #endif
253 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112860)
255 #if HAVE_MORE_FONTS
256 // The document has a split section inside a nested table, and also a table
257 // in the footer.
258 // This crashed the layout.
259 createSwDoc("tdf112860.fodt");
260 #endif
263 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113287)
265 #if HAVE_MORE_FONTS
266 createSwDoc("tdf113287.fodt");
267 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
268 assertXPath(pXmlDoc, "//page", 2);
269 sal_uInt32 nCellTop
270 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell[1]/infos/bounds", "top").toUInt32();
271 sal_uInt32 nSectionTop
272 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell[1]/section/infos/bounds", "top")
273 .toUInt32();
274 // Make sure section frame is inside the cell frame.
275 // Expected greater than 4593, was only 3714.
276 CPPUNIT_ASSERT_GREATER(nCellTop, nSectionTop);
277 #endif
280 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113445)
282 #if HAVE_MORE_FONTS
283 // Force multiple-page view.
284 createSwDoc("tdf113445.fodt");
285 SwDocShell* pDocShell = getSwDocShell();
286 SwView* pView = pDocShell->GetView();
287 pView->SetViewLayout(/*nColumns=*/2, /*bBookMode=*/false);
288 calcLayout();
290 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
291 assertXPath(pXmlDoc, "//page", 2);
292 sal_uInt32 nPage1Left = getXPath(pXmlDoc, "//page[1]/infos/bounds", "left").toUInt32();
293 sal_uInt32 nPage2Left = getXPath(pXmlDoc, "//page[2]/infos/bounds", "left").toUInt32();
294 // Make sure that page 2 is on the right hand side of page 1, not below it.
295 CPPUNIT_ASSERT_GREATER(nPage1Left, nPage2Left);
297 // Insert a new paragraph at the start of the document.
298 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
299 pWrtShell->StartOfSection();
300 pWrtShell->SplitNode();
301 pXmlDoc = parseLayoutDump();
303 // Make sure that Table2:C5 and Table2:D5 has its section frame inside the cell frame.
304 sal_uInt32 nCell3Top
305 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[3]/infos/bounds", "top")
306 .toUInt32();
307 sal_uInt32 nSection3Top
308 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[3]/section/infos/bounds",
309 "top")
310 .toUInt32();
311 CPPUNIT_ASSERT_GREATER(nCell3Top, nSection3Top);
312 sal_uInt32 nCell4Top
313 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[4]/infos/bounds", "top")
314 .toUInt32();
315 sal_uInt32 nSection4Top
316 = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[4]/section/infos/bounds",
317 "top")
318 .toUInt32();
319 CPPUNIT_ASSERT_GREATER(nCell4Top, nSection4Top);
320 // Also check if the two cells in the same row have the same top position.
321 // This was 4818, expected only 1672.
322 CPPUNIT_ASSERT_EQUAL(nCell3Top, nCell4Top);
323 #endif
326 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113686)
328 #if HAVE_MORE_FONTS
329 createSwDoc("tdf113686.fodt");
330 SwDoc* pDoc = getSwDoc();
331 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
332 assertXPath(pXmlDoc, "/root/page", 2);
333 SwNodeOffset nPage1LastNode(
334 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/tab/row/cell[1]/txt[last()]",
335 "txtNodeIndex")
336 .toUInt32());
337 CPPUNIT_ASSERT_EQUAL(u"Table2:A1-P10"_ustr,
338 pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
339 SwNodeOffset nPage2FirstNode(
340 getXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell[1]/section/txt[1]", "txtNodeIndex")
341 .toUInt32());
342 CPPUNIT_ASSERT_EQUAL(u"Table1:A1"_ustr,
343 pDoc->GetNodes()[nPage2FirstNode]->GetTextNode()->GetText());
345 // Remove page 2.
346 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
347 while (pWrtShell->GetCursor()->Start()->GetNodeIndex() < nPage1LastNode)
348 pWrtShell->Down(/*bSelect=*/false);
349 pWrtShell->EndPara();
350 for (int i = 0; i < 3; ++i)
351 pWrtShell->Up(/*bSelect=*/true);
352 pWrtShell->DelLeft();
354 // Assert that the second page is removed.
355 pXmlDoc = parseLayoutDump();
356 // This was still 2, content from 2nd page was not moved.
357 assertXPath(pXmlDoc, "/root/page", 1);
358 #endif
361 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTableInSectionInTable)
363 #if HAVE_MORE_FONTS
364 // The document has a table, containing a section, containing a nested
365 // table.
366 // This crashed the layout.
367 createSwDoc("i95698.odt");
368 #endif
371 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable)
373 #if HAVE_MORE_FONTS
374 // The document has a nested table, containing a multi-line section at a
375 // page boundary.
376 // This crashed the layout later in SwFrame::IsFootnoteAllowed().
377 createSwDoc("tdf112109.fodt");
378 #endif
381 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable2)
383 #if HAVE_MORE_FONTS
384 createSwDoc("split-section-in-nested-table.fodt");
385 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
386 sal_uInt32 nSection1
387 = getXPath(pXmlDoc, "//page[1]//body/tab/row/cell/tab/row/cell/section", "id").toUInt32();
388 sal_uInt32 nSection1Follow
389 = getXPath(pXmlDoc, "//page[1]//body/tab/row/cell/tab/row/cell/section", "follow")
390 .toUInt32();
391 // This failed, the section wasn't split inside a nested table.
392 sal_uInt32 nSection2
393 = getXPath(pXmlDoc, "//page[2]//body/tab/row/cell/tab/row/cell/section", "id").toUInt32();
394 sal_uInt32 nSection2Precede
395 = getXPath(pXmlDoc, "//page[2]//body/tab/row/cell/tab/row/cell/section", "precede")
396 .toUInt32();
398 // Make sure that the first's follow and the second's precede is correct.
399 CPPUNIT_ASSERT_EQUAL(nSection2, nSection1Follow);
400 CPPUNIT_ASSERT_EQUAL(nSection1, nSection2Precede);
401 #endif
404 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable3)
406 #if HAVE_MORE_FONTS
407 createSwDoc("tdf113153.fodt");
409 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
410 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
411 uno::UNO_QUERY);
412 uno::Reference<container::XNamed> xTable(xTables->getByIndex(1), uno::UNO_QUERY);
413 CPPUNIT_ASSERT_EQUAL(u"Table16"_ustr, xTable->getName());
415 uno::Reference<text::XTextTable> xRowSupplier(xTable, uno::UNO_QUERY);
416 uno::Reference<table::XTableRows> xRows = xRowSupplier->getRows();
417 uno::Reference<beans::XPropertySet> xRow(xRows->getByIndex(1), uno::UNO_QUERY);
418 xRow->setPropertyValue(u"IsSplitAllowed"_ustr, uno::Any(true));
419 // This never returned.
420 calcLayout();
422 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
423 sal_uInt32 nTable1 = getXPath(pXmlDoc, "//page[1]//body/tab", "id").toUInt32();
424 sal_uInt32 nTable1Follow = getXPath(pXmlDoc, "//page[1]//body/tab", "follow").toUInt32();
425 sal_uInt32 nTable2 = getXPath(pXmlDoc, "//page[2]//body/tab", "id").toUInt32();
426 sal_uInt32 nTable2Precede = getXPath(pXmlDoc, "//page[2]//body/tab", "precede").toUInt32();
427 sal_uInt32 nTable2Follow = getXPath(pXmlDoc, "//page[2]//body/tab", "follow").toUInt32();
428 sal_uInt32 nTable3 = getXPath(pXmlDoc, "//page[3]//body/tab", "id").toUInt32();
429 sal_uInt32 nTable3Precede = getXPath(pXmlDoc, "//page[3]//body/tab", "precede").toUInt32();
431 // Make sure the outer table frames are linked together properly.
432 CPPUNIT_ASSERT_EQUAL(nTable2, nTable1Follow);
433 CPPUNIT_ASSERT_EQUAL(nTable1, nTable2Precede);
434 CPPUNIT_ASSERT_EQUAL(nTable3, nTable2Follow);
435 CPPUNIT_ASSERT_EQUAL(nTable2, nTable3Precede);
436 #endif
439 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable4)
441 #if HAVE_MORE_FONTS
442 createSwDoc("tdf113520.fodt");
443 SwDoc* pDoc = getSwDoc();
444 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
445 assertXPath(pXmlDoc, "/root/page", 3);
446 SwNodeOffset nPage1LastNode(
447 getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/tab/row/cell[1]/section/txt[last()]",
448 "txtNodeIndex")
449 .toUInt32());
450 CPPUNIT_ASSERT_EQUAL(u"Section1:P10"_ustr,
451 pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
452 SwNodeOffset nPage3FirstNode(
453 getXPath(pXmlDoc, "/root/page[3]/body/tab/row/cell[1]/tab/row/cell[1]/section/txt[1]",
454 "txtNodeIndex")
455 .toUInt32());
456 CPPUNIT_ASSERT_EQUAL(u"Section1:P23"_ustr,
457 pDoc->GetNodes()[nPage3FirstNode]->GetTextNode()->GetText());
459 // Remove page 2.
460 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
461 while (pWrtShell->GetCursor()->Start()->GetNodeIndex() < nPage1LastNode)
462 pWrtShell->Down(/*bSelect=*/false);
463 pWrtShell->EndPara();
464 while (pWrtShell->GetCursor()->End()->GetNodeIndex() < nPage3FirstNode)
465 pWrtShell->Down(/*bSelect=*/true);
466 pWrtShell->EndPara(/*bSelect=*/true);
467 pWrtShell->DelLeft();
469 // Assert that the page is removed.
470 pXmlDoc = parseLayoutDump();
471 // This was 3, page 2 was emptied, but it wasn't removed.
472 assertXPath(pXmlDoc, "/root/page", 2);
474 // Make sure the outer table frames are linked together properly.
475 sal_uInt32 nTable1 = getXPath(pXmlDoc, "//page[1]//body/tab", "id").toUInt32();
476 sal_uInt32 nTable1Follow = getXPath(pXmlDoc, "//page[1]//body/tab", "follow").toUInt32();
477 sal_uInt32 nTable2 = getXPath(pXmlDoc, "//page[2]//body/tab", "id").toUInt32();
478 sal_uInt32 nTable2Precede = getXPath(pXmlDoc, "//page[2]//body/tab", "precede").toUInt32();
479 CPPUNIT_ASSERT_EQUAL(nTable2, nTable1Follow);
480 CPPUNIT_ASSERT_EQUAL(nTable1, nTable2Precede);
481 #endif
484 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112160)
486 #if HAVE_MORE_FONTS
487 // Assert that the A2 cell is on page 1.
488 createSwDoc("tdf112160.fodt");
489 SwDoc* pDoc = getSwDoc();
490 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
491 SwNodeOffset nA2CellNode(getXPath(pXmlDoc,
492 "/root/page[1]/body/tab/row[2]/cell[1]/section/txt[last()]",
493 "txtNodeIndex")
494 .toUInt32());
495 CPPUNIT_ASSERT_EQUAL(u"Table1.A2"_ustr,
496 pDoc->GetNodes()[nA2CellNode]->GetTextNode()->GetText());
498 // Append a new paragraph to the end of the A2 cell.
499 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
500 while (pWrtShell->GetCursor()->GetPointNode().GetIndex() < nA2CellNode)
501 pWrtShell->Down(/*bSelect=*/false);
502 pWrtShell->EndPara();
503 pWrtShell->SplitNode();
505 // Assert that after A2 got extended, D2 stays on page 1.
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(u"Table1.D2"_ustr,
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");
528 // Enter the table.
529 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
530 pWrtShell->Down(/*bSelect=*/false);
531 CPPUNIT_ASSERT(pWrtShell->IsCursorInTable());
532 // Enter the section.
533 pWrtShell->Down(/*bSelect=*/false);
534 CPPUNIT_ASSERT(pWrtShell->IsDirectlyInSection());
536 // Assert that we get the right paragraph object.
537 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
538 uno::Reference<text::XTextViewCursorSupplier> xController(xModel->getCurrentController(),
539 uno::UNO_QUERY);
540 uno::Reference<text::XTextRange> xViewCursor = xController->getViewCursor();
541 // This failed as there were no TextParagraph property.
542 auto xParagraph = getProperty<uno::Reference<text::XTextRange>>(xViewCursor->getStart(),
543 u"TextParagraph"_ustr);
544 CPPUNIT_ASSERT_EQUAL(u"In section"_ustr, xParagraph->getString());
547 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf99689TableOfContents)
549 createSwDoc("tdf99689.odt");
550 SwDoc* pDoc = getSwDoc();
551 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
552 pWrtShell->GotoNextTOXBase();
553 const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
554 pWrtShell->UpdateTableOf(*pTOXBase);
555 SwCursorShell* pShell(pDoc->GetEditShell());
556 CPPUNIT_ASSERT(pShell);
557 SwTextNode* pTitleNode = pShell->GetCursor()->GetPointNode().GetTextNode();
558 SwNodeIndex aIdx(*pTitleNode);
559 // skip the title
560 SwNodes::GoNext(&aIdx);
562 // skip the first header. No attributes there.
563 // next node should contain superscript
564 SwTextNode* pNext = static_cast<SwTextNode*>(SwNodes::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*>(SwNodes::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 = getSwDocShell()->GetWrtShell();
581 pWrtShell->GotoNextTOXBase();
582 const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
583 pWrtShell->UpdateTableOf(*pTOXBase);
584 SwCursorShell* pShell(pDoc->GetEditShell());
585 CPPUNIT_ASSERT(pShell);
586 SwTextNode* pTitleNode = pShell->GetCursor()->GetPointNode().GetTextNode();
587 SwNodeIndex aIdx(*pTitleNode);
589 // skip the title
590 // next node should contain subscript
591 SwTextNode* pNext = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
592 CPPUNIT_ASSERT(pNext->HasHints());
593 sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
594 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
596 // next node should contain superscript
597 pNext = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
598 CPPUNIT_ASSERT(pNext->HasHints());
599 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
600 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
603 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf99689TableOfTables)
605 createSwDoc("tdf99689_tables.odt");
606 SwDoc* pDoc = getSwDoc();
607 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
608 pWrtShell->GotoNextTOXBase();
609 const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
610 pWrtShell->UpdateTableOf(*pTOXBase);
611 SwCursorShell* pShell(pDoc->GetEditShell());
612 CPPUNIT_ASSERT(pShell);
613 SwTextNode* pTitleNode = pShell->GetCursor()->GetPointNode().GetTextNode();
614 SwNodeIndex aIdx(*pTitleNode);
616 // skip the title
617 // next node should contain superscript
618 SwTextNode* pNext = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
619 CPPUNIT_ASSERT(pNext->HasHints());
620 sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
621 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
623 // next node should contain subscript
624 pNext = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
625 CPPUNIT_ASSERT(pNext->HasHints());
626 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
627 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
630 // tdf#112448: Fix: take correct line height
632 // When line metrics is not calculated we need to call CalcRealHeight()
633 // before usage of the Height() and GetRealHeight().
634 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112448)
636 createSwDoc("tdf112448.odt");
638 // check actual number of line breaks in the paragraph
639 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
640 assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout", 2);
643 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113790)
645 createSwDoc("tdf113790.docx");
646 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
647 // Create the clipboard document.
648 SwDoc aClipboard;
649 aClipboard.SetClipBoard(true);
651 // Go to fourth line - to "ABCD" bulleted list item
652 pWrtShell->Down(/*bSelect=*/false, 4);
653 pWrtShell->SelPara(nullptr);
654 CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pWrtShell->GetSelText());
655 pWrtShell->Copy(aClipboard);
657 // Go down to next-to-last (empty) line above "Title3"
658 pWrtShell->Down(/*bSelect=*/false, 4);
659 pWrtShell->Paste(aClipboard);
661 // Save it as DOCX & load it again
662 saveAndReload(u"Office Open XML Text"_ustr);
665 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157937)
667 createSwDoc("tdf130088.docx");
668 SwDoc* pDoc = getSwDoc();
669 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
671 // select paragraph
672 pWrtShell->SelPara(nullptr);
674 // enable redlining
675 dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
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, u".uno:ChangeCaseRotateCase"_ustr, {});
686 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
688 // This resulted freezing
689 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
692 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157988)
694 createSwDoc("tdf130088.docx");
695 SwDoc* pDoc = getSwDoc();
697 // select the second word
698 dispatchCommand(mxComponent, u".uno:GoToNextWord"_ustr, {});
699 dispatchCommand(mxComponent, u".uno:SelectWord"_ustr, {});
701 // enable redlining
702 dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
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, u".uno:ChangeCaseRotateCase"_ustr, {});
715 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSodales"));
717 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
719 // This was false (missing revert of the tracked change)
720 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
722 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
724 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
726 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
728 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSodales"));
730 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
732 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
734 // tdf#141198 cycle case without selection: the word under the cursor
736 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
738 dispatchCommand(mxComponent, u".uno:GoRight"_ustr, {});
740 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
742 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
744 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
746 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSodales"));
748 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
750 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
753 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157667)
755 createSwDoc("tdf130088.docx");
756 SwDoc* pDoc = getSwDoc();
757 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
759 // select the first three words
760 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 25, /*bBasicCall=*/false);
762 // enable redlining
763 dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
764 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
765 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
767 // show changes
768 CPPUNIT_ASSERT_MESSAGE(
769 "redlines should be visible",
770 IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
772 // cycle case with change tracking
774 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
776 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
777 "Integer sodalesSodales tinciduntTincidunt tristique."));
779 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
781 // This was false (missing revert of the tracked change)
782 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));
784 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
786 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
787 "Integer sodalesINTEGER SODALES tincidunt tristique."));
789 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
791 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));
793 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
795 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
796 "Integer sodalesSodales tinciduntTincidunt tristique."));
798 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
800 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));
803 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf158039)
805 createSwDoc("tdf130088.docx");
806 SwDoc* pDoc = getSwDoc();
807 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
809 // select the first sentence
810 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 26, /*bBasicCall=*/false);
812 // enable redlining
813 dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
814 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
815 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
817 // show changes
818 CPPUNIT_ASSERT_MESSAGE(
819 "redlines should be visible",
820 IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
822 // cycle case with change tracking
824 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
826 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
827 "Integer sodalesSodales tinciduntTincidunt tristique."));
829 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
831 // This was false (missing revert of the tracked change)
832 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));
834 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
836 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
837 "Integer sodalesINTEGER SODALES tincidunt tristique."));
839 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
841 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
843 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
844 "Integer sodalesSodales tinciduntTincidunt tristique."));
846 dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
848 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));
851 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf108048)
853 createSwDoc();
855 uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({
856 { "Kind", uno::Any(sal_Int16(3)) },
857 { "TemplateName", uno::Any(u"Default Page Style"_ustr) },
858 { "PageNumber", uno::Any(sal_uInt16(6)) }, // Even number to avoid auto-inserted blank page
859 { "PageNumberFilled", uno::Any(true) },
861 dispatchCommand(mxComponent, u".uno:InsertBreak"_ustr, aPropertyValues);
862 CPPUNIT_ASSERT_EQUAL(2, getParagraphs());
863 CPPUNIT_ASSERT_EQUAL(2, getPages());
865 // The inserted page must have page number set to 6
866 uno::Reference<text::XTextRange> xPara = getParagraph(2);
867 sal_uInt16 nPageNumber = getProperty<sal_uInt16>(xPara, u"PageNumberOffset"_ustr);
868 CPPUNIT_ASSERT_EQUAL(sal_uInt16(6), nPageNumber);
871 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113481)
873 createSwDoc("tdf113481-IVS.odt");
874 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
876 // One backspace should completely remove the CJK ideograph variation sequence
877 pWrtShell->EndPara();
878 // Before: U+8FBA U+E0102. After: empty
879 pWrtShell->DelLeft();
880 const uno::Reference<text::XTextRange> xPara1 = getParagraph(1);
881 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xPara1->getString().getLength());
883 // Also variation sequence of weak characters that are treated as CJK script
884 pWrtShell->Down(false);
885 pWrtShell->EndPara();
886 // Before: U+4E2D U+2205 U+FE00. After: U+4E2D U+2205
887 pWrtShell->DelLeft();
888 const uno::Reference<text::XTextRange> xPara2 = getParagraph(2);
889 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xPara2->getString().getLength());
890 CPPUNIT_ASSERT_EQUAL(u'\x4E2D', xPara2->getString()[0]);
892 // Also variation sequence of other scripts
893 pWrtShell->Down(false);
894 pWrtShell->EndPara();
895 // Before: U+1820 U+180B. After: U+1820
896 pWrtShell->DelLeft();
897 const uno::Reference<text::XTextRange> xPara3 = getParagraph(3);
898 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xPara3->getString().getLength());
901 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf115013)
903 static constexpr OUString sColumnName(u"Name with spaces, \"quotes\" and \\backslashes"_ustr);
905 utl::TempFileNamed aTempDir(nullptr, true);
906 aTempDir.EnableKillingFile();
907 const OUString aWorkDir = aTempDir.GetURL();
909 //create new writer document
910 createSwDoc();
911 SwDoc* pDoc = getSwDoc();
914 // Load and register data source
915 OUString sDataSource
916 = SwDBManager::LoadAndRegisterDataSource(createFileURL(u"datasource.ods"), &aWorkDir);
917 CPPUNIT_ASSERT(!sDataSource.isEmpty());
919 // Insert a new field type for the mailmerge field
920 SwDBData aDBData;
921 aDBData.sDataSource = sDataSource;
922 aDBData.sCommand = "Sheet1";
923 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
924 CPPUNIT_ASSERT(pWrtShell);
925 SwDBFieldType* pFieldType = static_cast<SwDBFieldType*>(
926 pWrtShell->InsertFieldType(SwDBFieldType(pDoc, sColumnName, aDBData)));
927 CPPUNIT_ASSERT(pFieldType);
929 // Insert the field into document
930 SwDBField aField(pFieldType);
931 pWrtShell->InsertField2(aField);
933 // Save it as DOCX & load it again
934 saveAndReload(u"Office Open XML Text"_ustr);
935 pDoc = getSwDoc();
936 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
937 CPPUNIT_ASSERT(pWrtShell);
938 SwCursorShell* pShell(pDoc->GetEditShell());
939 CPPUNIT_ASSERT(pShell);
940 SwPaM* pCursor = pShell->GetCursor();
941 CPPUNIT_ASSERT(pCursor);
943 // Get the field at the beginning of the document
944 SwDBField* pField = dynamic_cast<SwDBField*>(SwCursorShell::GetFieldAtCursor(pCursor, true));
945 CPPUNIT_ASSERT(pField);
946 OUString sColumn = static_cast<SwDBFieldType*>(pField->GetTyp())->GetColumnName();
947 // The column name must come correct after round trip
948 CPPUNIT_ASSERT_EQUAL(sColumnName, sColumn);
951 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf115065)
953 // In the document, the tables have table style assigned
954 // Source table (first one) has two rows;
955 // destination (second one) has only one row
956 createSwDoc("tdf115065.odt");
957 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
958 CPPUNIT_ASSERT(pWrtShell);
960 pWrtShell->GotoTable(u"Table2"_ustr);
961 SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
962 // Destination point is the middle of the first cell of second table
963 Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
965 pWrtShell->GotoTable(u"Table1"_ustr);
966 aRect = pWrtShell->GetCurrFrame()->getFrameArea();
967 // Source point is the middle of the first cell of first table
968 Point ptFrom(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
970 pWrtShell->SelTableCol();
971 // The copy operation (or closing document after that) segfaulted
972 pWrtShell->Copy(*pWrtShell, ptFrom, ptTo);
975 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf84806_MovingMultipleTableRows)
977 // Moving of multiple table rows.
978 // Source table (first one) has two rows;
979 // destination (second one) has only one row
980 createSwDoc("tdf115065.odt");
981 SwDoc* pDoc = getSwDoc();
982 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
983 CPPUNIT_ASSERT(pWrtShell);
985 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
986 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
987 uno::UNO_QUERY);
988 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
989 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
990 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
991 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table2"_ustr));
992 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
993 uno::UNO_QUERY);
994 uno::Reference<text::XTextTable> xTable2(xTableNames->getByName(u"Table2"_ustr),
995 uno::UNO_QUERY);
996 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
997 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2->getRows()->getCount());
999 // without redlining
1000 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
1001 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1003 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
1005 pWrtShell->GotoTable(u"Table2"_ustr);
1006 SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
1007 // Destination point is the middle of the first cell of second table
1008 Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
1010 // Move rows of the first table into the second table
1011 pWrtShell->GotoTable(u"Table1"_ustr);
1012 pWrtShell->SelTable();
1013 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
1014 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
1016 // This was 2 tables
1017 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
1018 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());
1020 // Undo results 2 tables
1021 rUndoManager.Undo();
1022 uno::Reference<container::XIndexAccess> xTables2(xTablesSupplier->getTextTables(),
1023 uno::UNO_QUERY);
1024 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables2->getCount());
1025 uno::Reference<text::XTextTable> xTable1b(xTableNames->getByName(u"Table1"_ustr),
1026 uno::UNO_QUERY);
1027 uno::Reference<text::XTextTable> xTable2b(xTableNames->getByName(u"Table2"_ustr),
1028 uno::UNO_QUERY);
1029 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
1030 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());
1032 // FIXME assert with Redo()
1035 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf147181_TrackedMovingOfMultipleTableRows)
1037 // Tracked moving of multiple table rows.
1038 // Source table (first one) has two rows;
1039 // destination (second one) has only one row
1040 createSwDoc("tdf115065.odt");
1041 SwDoc* pDoc = getSwDoc();
1042 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1043 CPPUNIT_ASSERT(pWrtShell);
1045 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1046 uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
1047 uno::UNO_QUERY);
1048 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
1049 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1050 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
1051 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table2"_ustr));
1052 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
1053 uno::UNO_QUERY);
1054 uno::Reference<text::XTextTable> xTable2(xTableNames->getByName(u"Table2"_ustr),
1055 uno::UNO_QUERY);
1056 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
1057 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2->getRows()->getCount());
1059 // FIXME: doesn't work with empty rows, yet
1060 pWrtShell->Insert(u"x"_ustr);
1061 pWrtShell->Down(false);
1062 pWrtShell->Insert(u"x"_ustr);
1064 // enable redlining
1065 dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
1066 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
1067 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1069 // show changes
1070 CPPUNIT_ASSERT_MESSAGE(
1071 "redlines should be visible",
1072 IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
1074 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
1076 pWrtShell->GotoTable(u"Table2"_ustr);
1077 SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
1078 // Destination point is the middle of the first cell of second table
1079 Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);
1081 // Move rows of the first table into the second table
1082 pWrtShell->GotoTable(u"Table1"_ustr);
1083 pWrtShell->SelTable();
1084 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
1085 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
1087 // still 2 tables, but the second one has got 3 rows
1088 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
1089 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
1090 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());
1092 // accept changes results 1 table (removing moved table)
1093 dispatchCommand(mxComponent, u".uno:AcceptAllTrackedChanges"_ustr, {});
1094 uno::Reference<container::XIndexAccess> xTables2(xTablesSupplier->getTextTables(),
1095 uno::UNO_QUERY);
1096 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables2->getCount());
1097 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());
1099 // Undo results 2 tables
1100 rUndoManager.Undo();
1101 rUndoManager.Undo();
1102 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables2->getCount());
1103 uno::Reference<text::XTextTable> xTable1b(xTableNames->getByName(u"Table1"_ustr),
1104 uno::UNO_QUERY);
1105 uno::Reference<text::XTextTable> xTable2b(xTableNames->getByName(u"Table2"_ustr),
1106 uno::UNO_QUERY);
1107 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
1108 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());
1110 // reject changes results 2 table again, with the original row counts
1111 dispatchCommand(mxComponent, u".uno:RejectAllTrackedChanges"_ustr, {});
1112 uno::Reference<container::XIndexAccess> xTables3(xTablesSupplier->getTextTables(),
1113 uno::UNO_QUERY);
1114 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables3->getCount());
1115 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
1116 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());
1119 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157492_TrackedMovingRow)
1121 createSwDoc();
1122 SwDoc* pDoc = getSwDoc();
1123 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1124 CPPUNIT_ASSERT(pWrtShell);
1126 // Create a table
1127 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1128 (void)&pWrtShell->InsertTable(TableOpt, 4, 3);
1130 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1131 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1132 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
1133 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
1134 uno::UNO_QUERY);
1135 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
1136 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());
1138 // fill table with data
1139 SwXTextDocument* pTextDoc = getSwTextDoc();
1140 for (int i = 0; i < 3; ++i)
1142 pWrtShell->Insert(u"x"_ustr);
1143 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RIGHT);
1146 Scheduler::ProcessEventsToIdle();
1148 uno::Reference<text::XTextRange> xCellA1(xTable1->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
1149 xCellA1->setString(u"A1"_ustr);
1150 uno::Reference<text::XTextRange> xCellB1(xTable1->getCellByName(u"B1"_ustr), uno::UNO_QUERY);
1151 xCellB1->setString(u"B1"_ustr);
1152 uno::Reference<text::XTextRange> xCellC1(xTable1->getCellByName(u"C1"_ustr), uno::UNO_QUERY);
1153 xCellC1->setString(u"C1"_ustr);
1155 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1156 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[1]/txt", u"A1");
1157 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[2]/txt", u"B1");
1158 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[3]/txt", u"C1");
1160 // enable redlining
1161 dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
1162 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
1163 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1165 // Move first column of the table before the third column by drag & drop
1166 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1167 SwFrame* pPage = pLayout->Lower();
1168 SwFrame* pBody = pPage->GetLower();
1169 SwFrame* pTable = pBody->GetLower();
1170 SwFrame* pRow1 = pTable->GetLower();
1171 SwFrame* pCellA1 = pRow1->GetLower();
1172 SwFrame* pRow3 = pRow1->GetNext()->GetNext();
1173 SwFrame* pCellA3 = pRow3->GetLower();
1174 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1175 const SwRect& rCellA3Rect = pCellA3->getFrameArea();
1176 Point ptTo(rCellA3Rect.Left() + rCellA3Rect.Width() / 2,
1177 rCellA3Rect.Top() + rCellA3Rect.Height() / 2);
1178 // select first table row by using the middle point of the left border of row 1
1179 Point ptRow(rCellA1Rect.Left() - 5, rCellA1Rect.Top() + rCellA1Rect.Height() / 2);
1180 pWrtShell->SelectTableRowCol(ptRow);
1182 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
1184 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
1186 // reject changes results 4 rows again, not 5
1187 dispatchCommand(mxComponent, u".uno:RejectAllTrackedChanges"_ustr, {});
1189 xTableNames = xTablesSupplier->getTextTables();
1190 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
1191 uno::Reference<text::XTextTable> xTable2(xTableNames->getByName(u"Table1"_ustr),
1192 uno::UNO_QUERY);
1193 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getColumns()->getCount());
1194 // This was 5 (moving row without change tracking)
1195 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable2->getRows()->getCount());
1198 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf154599_MovingColumn)
1200 createSwDoc();
1201 SwDoc* pDoc = getSwDoc();
1202 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1203 CPPUNIT_ASSERT(pWrtShell);
1205 // Create a table with less columns than rows
1206 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1207 (void)&pWrtShell->InsertTable(TableOpt, 4, 3);
1209 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1210 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1211 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
1212 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
1213 uno::UNO_QUERY);
1214 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
1215 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());
1217 // without redlining
1218 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
1219 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1221 // Move first column of the table before the third column by drag & drop
1223 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1224 SwFrame* pPage = pLayout->Lower();
1225 SwFrame* pBody = pPage->GetLower();
1226 SwFrame* pTable = pBody->GetLower();
1227 SwFrame* pRow1 = pTable->GetLower();
1228 SwFrame* pCellA1 = pRow1->GetLower();
1229 SwFrame* pCellC1 = pCellA1->GetNext()->GetNext();
1230 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1231 const SwRect& rCellC1Rect = pCellC1->getFrameArea();
1232 Point ptTo(rCellC1Rect.Left() + rCellC1Rect.Width() / 2,
1233 rCellC1Rect.Top() + rCellC1Rect.Height() / 2);
1234 // select first table column by using the middle point of the top border of column A
1235 Point ptColumn(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() - 5);
1236 pWrtShell->SelectTableRowCol(ptColumn);
1238 // This crashed here before the fix.
1239 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
1241 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
1243 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
1244 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());
1247 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf155846_MovingColumn)
1249 createSwDoc();
1250 SwDoc* pDoc = getSwDoc();
1251 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1252 CPPUNIT_ASSERT(pWrtShell);
1254 // Create a table
1255 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1256 (void)&pWrtShell->InsertTable(TableOpt, 4, 3);
1258 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1259 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1260 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
1261 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
1262 uno::UNO_QUERY);
1263 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
1264 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());
1266 // fill table with data
1267 SwXTextDocument* pTextDoc = getSwTextDoc();
1268 for (int i = 0; i < 4; ++i)
1270 pWrtShell->Insert(u"x"_ustr);
1271 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_DOWN);
1274 Scheduler::ProcessEventsToIdle();
1276 uno::Reference<text::XTextRange> xCellA1(xTable1->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
1277 xCellA1->setString(u"A1"_ustr);
1278 uno::Reference<text::XTextRange> xCellA2(xTable1->getCellByName(u"A2"_ustr), uno::UNO_QUERY);
1279 xCellA2->setString(u"A2"_ustr);
1280 uno::Reference<text::XTextRange> xCellA3(xTable1->getCellByName(u"A3"_ustr), uno::UNO_QUERY);
1281 xCellA3->setString(u"A3"_ustr);
1282 uno::Reference<text::XTextRange> xCellA4(xTable1->getCellByName(u"A4"_ustr), uno::UNO_QUERY);
1283 xCellA4->setString(u"A4"_ustr);
1285 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1286 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[1]/txt", u"A1");
1287 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[2]/cell[1]/txt", u"A2");
1288 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[3]/cell[1]/txt", u"A3");
1289 assertXPathContent(pXmlDoc, "/root/page/body/tab/row[4]/cell[1]/txt", u"A4");
1291 // enable redlining
1292 dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
1293 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
1294 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1296 // Move first column of the table before the third column by drag & drop
1297 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1298 SwFrame* pPage = pLayout->Lower();
1299 SwFrame* pBody = pPage->GetLower();
1300 SwFrame* pTable = pBody->GetLower();
1301 SwFrame* pRow1 = pTable->GetLower();
1302 SwFrame* pCellA1 = pRow1->GetLower();
1303 SwFrame* pCellC1 = pCellA1->GetNext()->GetNext();
1304 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1305 const SwRect& rCellC1Rect = pCellC1->getFrameArea();
1306 Point ptTo(rCellC1Rect.Left() + rCellC1Rect.Width() / 2,
1307 rCellC1Rect.Top() + rCellC1Rect.Height() / 2);
1308 // select first table column by using the middle point of the top border of column A
1309 Point ptColumn(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() - 5);
1310 pWrtShell->SelectTableRowCol(ptColumn);
1312 // This crashed here before the fix.
1313 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
1315 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
1317 // reject changes results 3 columns again, not 4
1318 dispatchCommand(mxComponent, u".uno:RejectAllTrackedChanges"_ustr, {});
1320 xTableNames = xTablesSupplier->getTextTables();
1321 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
1322 uno::Reference<text::XTextTable> xTable2(xTableNames->getByName(u"Table1"_ustr),
1323 uno::UNO_QUERY);
1324 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable2->getRows()->getCount());
1325 // This was 4 (moving column without change tracking)
1326 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getColumns()->getCount());
1329 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf154771_MovingMultipleColumns)
1331 createSwDoc();
1332 SwDoc* pDoc = getSwDoc();
1333 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1334 CPPUNIT_ASSERT(pWrtShell);
1336 // Create a table with less columns than rows
1337 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1338 (void)&pWrtShell->InsertTable(TableOpt, 5, 4);
1340 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1341 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1342 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
1343 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
1344 uno::UNO_QUERY);
1345 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xTable1->getRows()->getCount());
1346 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getColumns()->getCount());
1348 // without redlining
1349 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
1350 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1352 // Move first two columns of the table before column D by drag & drop
1354 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1355 SwFrame* pPage = pLayout->Lower();
1356 SwFrame* pBody = pPage->GetLower();
1357 SwFrame* pTable = pBody->GetLower();
1358 SwFrame* pRow1 = pTable->GetLower();
1359 SwFrame* pCellA1 = pRow1->GetLower();
1360 SwFrame* pCellB1 = pCellA1->GetNext();
1361 SwFrame* pCellD1 = pCellB1->GetNext()->GetNext();
1362 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1363 const SwRect& rCellB1Rect = pCellB1->getFrameArea();
1364 const SwRect& rCellD1Rect = pCellD1->getFrameArea();
1365 Point ptTo(rCellD1Rect.Left() + rCellD1Rect.Width() / 2,
1366 rCellD1Rect.Top() + rCellD1Rect.Height() / 2);
1367 // select first two table columns by using
1368 // the middle point of the top border of column A
1369 // and middle point of the top border of column B
1370 Point ptColumnA(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() - 5);
1371 const Point ptColumnB(rCellB1Rect.Left() + rCellB1Rect.Width() / 2, rCellB1Rect.Top() - 5);
1372 pWrtShell->SelectTableRowCol(ptColumnA, &ptColumnB);
1374 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
1375 xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);
1377 CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xTable1->getRows()->getCount());
1378 // This was 5 before the fix (only the first selected column was moved, the
1379 // other ones were copied instead of moving)
1380 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getColumns()->getCount());
1383 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf44773)
1385 // allow resizing table rows, if cursor outside the table
1386 createSwDoc();
1387 SwDoc* pDoc = getSwDoc();
1388 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1389 CPPUNIT_ASSERT(pWrtShell);
1391 // insert an empty paragraph
1392 pWrtShell->SplitNode();
1394 // create a table
1395 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1396 (void)&pWrtShell->InsertTable(TableOpt, 2, 1);
1398 // the cursor is not inside the table
1399 CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
1401 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1402 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1403 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
1404 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
1405 uno::UNO_QUERY);
1406 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
1407 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable1->getColumns()->getCount());
1409 Scheduler::ProcessEventsToIdle();
1411 // set table row height by drag & drop
1412 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1414 SwFrame* pPage = pLayout->Lower();
1415 SwFrame* pBody = pPage->GetLower();
1416 SwFrame* pTable = pBody->GetLower()->GetNext();
1417 SwFrame* pRow1 = pTable->GetLower();
1418 CPPUNIT_ASSERT(pRow1->IsRowFrame());
1419 SwFrame* pCellA1 = pRow1->GetLower();
1420 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1421 auto nRowHeight = rCellA1Rect.Height();
1422 // select center of the bottom border of the first table cell
1423 Point ptFrom(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + nRowHeight);
1424 // double the row height
1425 Point ptTo(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + 2 * nRowHeight);
1426 vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
1427 Point aFrom = rEditWin.LogicToPixel(ptFrom);
1428 MouseEvent aClickEvent(aFrom, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
1429 MOUSE_LEFT);
1430 rEditWin.MouseButtonDown(aClickEvent);
1431 Point aTo = rEditWin.LogicToPixel(ptTo);
1432 MouseEvent aMoveEvent(aTo, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
1433 MOUSE_LEFT);
1434 TrackingEvent aTEvt(aMoveEvent, TrackingEventFlags::Repeat);
1435 // drag & drop of cell border inside the document (and outside the table)
1436 // still based on the ruler code, use that to simulate dragging
1437 getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt);
1438 TrackingEvent aTEvt2(aMoveEvent, TrackingEventFlags::End);
1439 getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt2);
1440 Scheduler::ProcessEventsToIdle();
1441 rEditWin.CaptureMouse();
1442 rEditWin.ReleaseMouse();
1444 // this was 396 (not modified row height previously)
1445 CPPUNIT_ASSERT_GREATER(tools::Long(750), pCellA1->getFrameArea().Height());
1448 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157833)
1450 // allow resizing table rows & columns using a minimal hit area
1451 createSwDoc();
1452 SwDoc* pDoc = getSwDoc();
1453 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1454 CPPUNIT_ASSERT(pWrtShell);
1456 // insert an empty paragraph
1457 pWrtShell->SplitNode();
1459 // create a table
1460 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1461 (void)&pWrtShell->InsertTable(TableOpt, 2, 1);
1463 // the cursor is not inside the table
1464 CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
1466 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1467 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1468 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
1469 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
1470 uno::UNO_QUERY);
1471 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
1472 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable1->getColumns()->getCount());
1474 Scheduler::ProcessEventsToIdle();
1476 // set table row height by drag & drop
1477 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1479 SwFrame* pPage = pLayout->Lower();
1480 SwFrame* pBody = pPage->GetLower();
1481 SwFrame* pTable = pBody->GetLower()->GetNext();
1482 SwFrame* pRow1 = pTable->GetLower();
1483 CPPUNIT_ASSERT(pRow1->IsRowFrame());
1484 SwFrame* pCellA1 = pRow1->GetLower();
1485 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1486 auto nRowHeight = rCellA1Rect.Height();
1487 // select center of the bottom border of the first table cell
1488 Point ptFrom(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + nRowHeight);
1489 // double the row height
1490 Point ptTo(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + 2 * nRowHeight);
1491 vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
1492 Point aFrom = rEditWin.LogicToPixel(ptFrom);
1493 Point aArea(aFrom.X(), aFrom.Y() + 2);
1494 MouseEvent aClickEvent(aArea, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
1495 MOUSE_LEFT);
1496 rEditWin.MouseButtonDown(aClickEvent);
1497 Point aTo = rEditWin.LogicToPixel(ptTo);
1498 MouseEvent aMoveEvent(aTo, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
1499 MOUSE_LEFT);
1500 TrackingEvent aTEvt(aMoveEvent, TrackingEventFlags::Repeat);
1501 // drag & drop of cell border inside the document (and outside the table)
1502 // still based on the ruler code, use that to simulate dragging
1503 getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt);
1504 TrackingEvent aTEvt2(aMoveEvent, TrackingEventFlags::End);
1505 getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt2);
1506 Scheduler::ProcessEventsToIdle();
1507 rEditWin.CaptureMouse();
1508 rEditWin.ReleaseMouse();
1510 // this was 396 (not modified row height previously, when clicking only in a 2-pixel distance
1511 // from the center of the border)
1512 CPPUNIT_ASSERT_GREATER(tools::Long(750), pCellA1->getFrameArea().Height());
1515 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf155692)
1517 // allow resizing table rows & columns using a normal hit area
1518 createSwDoc();
1519 SwDoc* pDoc = getSwDoc();
1520 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1521 CPPUNIT_ASSERT(pWrtShell);
1523 // insert an empty paragraph
1524 pWrtShell->SplitNode();
1526 // create a table
1527 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
1528 (void)&pWrtShell->InsertTable(TableOpt, 2, 1);
1530 // the cursor is not inside the table
1531 CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
1533 uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
1534 uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
1535 CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
1536 uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
1537 uno::UNO_QUERY);
1538 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
1539 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable1->getColumns()->getCount());
1541 Scheduler::ProcessEventsToIdle();
1543 // set table row height by drag & drop
1544 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1546 SwFrame* pPage = pLayout->Lower();
1547 SwFrame* pBody = pPage->GetLower();
1548 SwFrame* pTable = pBody->GetLower()->GetNext();
1549 SwFrame* pRow1 = pTable->GetLower();
1550 CPPUNIT_ASSERT(pRow1->IsRowFrame());
1551 SwFrame* pCellA1 = pRow1->GetLower();
1552 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1553 auto nRowHeight = rCellA1Rect.Height();
1554 // select center of the bottom border of the first table cell
1555 Point ptFrom(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + nRowHeight);
1556 // double the row height
1557 Point ptTo(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + 2 * nRowHeight);
1558 vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
1559 Point aFrom = rEditWin.LogicToPixel(ptFrom);
1560 Point aArea(aFrom.X(), aFrom.Y() + 5);
1561 MouseEvent aClickEvent(aArea, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
1562 MOUSE_LEFT);
1563 rEditWin.MouseButtonDown(aClickEvent);
1564 Point aTo = rEditWin.LogicToPixel(ptTo);
1565 MouseEvent aMoveEvent(aTo, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
1566 MOUSE_LEFT);
1567 TrackingEvent aTEvt(aMoveEvent, TrackingEventFlags::Repeat);
1568 // drag & drop of cell border inside the document (and outside the table)
1569 // still based on the ruler code, use that to simulate dragging
1570 getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt);
1571 TrackingEvent aTEvt2(aMoveEvent, TrackingEventFlags::End);
1572 getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt2);
1573 Scheduler::ProcessEventsToIdle();
1574 rEditWin.CaptureMouse();
1575 rEditWin.ReleaseMouse();
1577 // this was 396 (not modified row height previously, when clicking only in a 5-pixel distance
1578 // from the center of the border)
1579 CPPUNIT_ASSERT_GREATER(tools::Long(750), pCellA1->getFrameArea().Height());
1582 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf160842)
1584 createSwDoc("tdf160842.fodt");
1585 SwDoc* pDoc = getSwDoc();
1586 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1587 CPPUNIT_ASSERT(pWrtShell);
1588 // the cursor is not in the table
1589 CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
1591 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1592 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
1593 CPPUNIT_ASSERT(pPage);
1594 const SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
1595 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
1596 auto pPageFly = dynamic_cast<SwFlyAtContentFrame*>(rPageObjs[0]);
1597 CPPUNIT_ASSERT(pPageFly);
1598 auto pTable = dynamic_cast<SwTabFrame*>(pPageFly->GetLower());
1599 CPPUNIT_ASSERT(pTable);
1600 auto pRow2 = pTable->GetLower()->GetNext();
1601 CPPUNIT_ASSERT(pRow2->IsRowFrame());
1602 auto pCellA2 = pRow2->GetLower();
1603 CPPUNIT_ASSERT(pCellA2);
1604 const SwRect& rCellA2Rect = pCellA2->getFrameArea();
1605 auto nRowHeight = rCellA2Rect.Height();
1606 // select center of the bottom cell
1607 Point ptFrom(rCellA2Rect.Left() + rCellA2Rect.Width() / 2, rCellA2Rect.Top() + nRowHeight / 2);
1608 vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
1609 Point aFrom = rEditWin.LogicToPixel(ptFrom);
1610 MouseEvent aClickEvent(aFrom, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1611 rEditWin.MouseButtonDown(aClickEvent);
1612 rEditWin.MouseButtonUp(aClickEvent);
1614 // the cursor is in the table
1615 CPPUNIT_ASSERT(pWrtShell->IsCursorInTable());
1618 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf160836)
1620 createSwDoc("tdf160842.fodt");
1621 SwDoc* pDoc = getSwDoc();
1622 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1623 CPPUNIT_ASSERT(pWrtShell);
1625 // set table row height by drag & drop at images cropped by the fixed row height
1626 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1627 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
1628 CPPUNIT_ASSERT(pPage);
1629 const SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
1630 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
1631 auto pPageFly = dynamic_cast<SwFlyAtContentFrame*>(rPageObjs[0]);
1632 CPPUNIT_ASSERT(pPageFly);
1633 auto pTable = dynamic_cast<SwTabFrame*>(pPageFly->GetLower());
1634 CPPUNIT_ASSERT(pTable);
1635 auto pRow1 = pTable->GetLower();
1636 CPPUNIT_ASSERT(pRow1->IsRowFrame());
1637 auto pCellA1 = pRow1->GetLower();
1638 CPPUNIT_ASSERT(pCellA1);
1639 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1640 auto nRowHeight = rCellA1Rect.Height();
1641 // select center of the bottom border of the first table cell
1642 Point ptFrom(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + nRowHeight);
1643 // halve the row height
1644 Point ptTo(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + 0.5 * nRowHeight);
1645 vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
1646 Point aFrom = rEditWin.LogicToPixel(ptFrom);
1647 MouseEvent aClickEvent(aFrom, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
1648 MOUSE_LEFT);
1649 rEditWin.MouseButtonDown(aClickEvent);
1650 Point aTo = rEditWin.LogicToPixel(ptTo);
1651 MouseEvent aMoveEvent(aTo, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
1652 MOUSE_LEFT);
1653 TrackingEvent aTEvt(aMoveEvent, TrackingEventFlags::Repeat);
1654 // drag & drop of cell border inside the document (and outside the table)
1655 // still based on the ruler code, use that to simulate dragging
1656 getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt);
1657 TrackingEvent aTEvt2(aMoveEvent, TrackingEventFlags::End);
1658 getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt2);
1659 Scheduler::ProcessEventsToIdle();
1660 rEditWin.CaptureMouse();
1661 rEditWin.ReleaseMouse();
1663 // this was 3910 (not modified row height previously)
1664 CPPUNIT_ASSERT_LESS(tools::Long(2000), pCellA1->getFrameArea().Height());
1667 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf161261)
1669 createSwDoc("tdf160842.fodt");
1670 SwDoc* pDoc = getSwDoc();
1671 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1672 CPPUNIT_ASSERT(pWrtShell);
1673 // the cursor is not in the table
1674 CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
1676 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1677 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
1678 CPPUNIT_ASSERT(pPage);
1679 const SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
1680 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
1681 auto pPageFly = dynamic_cast<SwFlyAtContentFrame*>(rPageObjs[0]);
1682 CPPUNIT_ASSERT(pPageFly);
1683 auto pTable = dynamic_cast<SwTabFrame*>(pPageFly->GetLower());
1684 CPPUNIT_ASSERT(pTable);
1685 auto pRow1 = pTable->GetLower();
1686 CPPUNIT_ASSERT(pRow1->IsRowFrame());
1687 auto pCellA1 = pRow1->GetLower();
1688 CPPUNIT_ASSERT(pCellA1);
1689 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1690 auto nRowHeight = rCellA1Rect.Height();
1692 // select image by clicking on it at the center of the upper cell
1693 Point ptFrom(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + nRowHeight / 2);
1694 vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
1695 Point aFrom = rEditWin.LogicToPixel(ptFrom);
1696 MouseEvent aClickEvent(aFrom, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1697 rEditWin.MouseButtonDown(aClickEvent);
1698 rEditWin.MouseButtonUp(aClickEvent);
1700 // Then make sure that the image is selected:
1701 SelectionType eType = pWrtShell->GetSelectionType();
1702 CPPUNIT_ASSERT_EQUAL(SelectionType::Graphic, eType);
1704 uno::Reference<drawing::XShape> xShape = getShape(2);
1705 CPPUNIT_ASSERT(xShape.is());
1707 // zoom image by drag & drop using right bottom handle of the image
1708 const SwRect& rSelRect = pWrtShell->GetAnyCurRect(CurRectType::Frame);
1709 Point ptFromHandle(rSelRect.Right(), rSelRect.Bottom());
1710 Point aFromHandle = rEditWin.LogicToPixel(ptFromHandle);
1711 Point ptTo(rSelRect.Left() + rSelRect.Width() * 1.5, rSelRect.Top() + rSelRect.Height() * 1.5);
1712 Point aTo = rEditWin.LogicToPixel(ptTo);
1713 MouseEvent aClickEvent2(aFromHandle, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1714 rEditWin.MouseButtonDown(aClickEvent2);
1715 MouseEvent aClickEvent3(aTo, 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
1716 rEditWin.MouseMove(aClickEvent3);
1717 rEditWin.MouseMove(aClickEvent3);
1718 MouseEvent aClickEvent4(aTo, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1719 rEditWin.MouseButtonUp(aClickEvent4);
1720 Scheduler::ProcessEventsToIdle();
1722 // Make sure image is greater than before, instead of minimizing it to the cell size
1723 // This was 8707 and 6509
1724 CPPUNIT_ASSERT_GREATER(sal_Int32(10000), xShape->getSize().Width);
1725 CPPUNIT_ASSERT_GREATER(sal_Int32(8000), xShape->getSize().Height);
1728 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf161332)
1730 createSwDoc("tdf160842.fodt");
1731 SwDoc* pDoc = getSwDoc();
1732 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1733 CPPUNIT_ASSERT(pWrtShell);
1734 // the cursor is not in the table
1735 CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
1737 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1738 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
1739 CPPUNIT_ASSERT(pPage);
1740 const SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
1741 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
1742 auto pPageFly = dynamic_cast<SwFlyAtContentFrame*>(rPageObjs[0]);
1743 CPPUNIT_ASSERT(pPageFly);
1744 auto pTable = dynamic_cast<SwTabFrame*>(pPageFly->GetLower());
1745 CPPUNIT_ASSERT(pTable);
1746 auto pRow1 = pTable->GetLower();
1747 CPPUNIT_ASSERT(pRow1->IsRowFrame());
1748 auto pCellA1 = pRow1->GetLower();
1749 CPPUNIT_ASSERT(pCellA1);
1750 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1751 auto nRowHeight = rCellA1Rect.Height();
1753 // select text frame by clicking on it at the right side of the upper cell
1754 Point ptFrom(rCellA1Rect.Left() + rCellA1Rect.Width(), rCellA1Rect.Top() + nRowHeight / 2);
1755 vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
1756 Point aFrom = rEditWin.LogicToPixel(ptFrom);
1757 MouseEvent aClickEvent(aFrom, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1758 rEditWin.MouseButtonDown(aClickEvent);
1759 rEditWin.MouseButtonUp(aClickEvent);
1761 // Then make sure that the text frame is selected:
1762 SelectionType eType = pWrtShell->GetSelectionType();
1763 // This was false (SelectionType::Graphic)
1764 CPPUNIT_ASSERT_EQUAL(SelectionType::Frame, eType);
1766 // remove selection
1767 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
1769 // select text frame by clicking on it at the right side of the bottom cell
1770 auto pRow2 = pRow1->GetNext();
1771 CPPUNIT_ASSERT(pRow2->IsRowFrame());
1772 auto pCellA2 = pRow2->GetLower();
1773 CPPUNIT_ASSERT(pCellA2);
1774 const SwRect& rCellA2Rect = pCellA2->getFrameArea();
1775 auto nRow2Height = rCellA2Rect.Height();
1776 Point ptFrom2(rCellA2Rect.Left() + rCellA2Rect.Width(), rCellA2Rect.Top() + nRow2Height / 2);
1777 Point aFrom2 = rEditWin.LogicToPixel(ptFrom2);
1778 MouseEvent aClickEvent2(aFrom2, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1779 rEditWin.MouseButtonDown(aClickEvent2);
1780 rEditWin.MouseButtonUp(aClickEvent2);
1782 // Then make sure that the text frame is selected:
1783 SelectionType eType2 = pWrtShell->GetSelectionType();
1784 // This was false (SelectionType::Graphic)
1785 CPPUNIT_ASSERT_EQUAL(SelectionType::Frame, eType2);
1788 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf161426)
1790 createSwDoc("tdf161426.fodt");
1791 SwDoc* pDoc = getSwDoc();
1792 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1793 CPPUNIT_ASSERT(pWrtShell);
1794 // the cursor is not in the table
1795 CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
1797 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1798 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
1799 CPPUNIT_ASSERT(pPage);
1800 const SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
1801 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
1802 auto pPageFly = dynamic_cast<SwFlyAtContentFrame*>(rPageObjs[0]);
1803 CPPUNIT_ASSERT(pPageFly);
1804 auto pTable = dynamic_cast<SwTabFrame*>(pPageFly->GetLower());
1805 CPPUNIT_ASSERT(pTable);
1806 auto pRow1 = pTable->GetLower();
1807 CPPUNIT_ASSERT(pRow1->IsRowFrame());
1808 auto pCellA1 = pRow1->GetLower();
1809 CPPUNIT_ASSERT(pCellA1);
1810 auto pCellB1 = pCellA1->GetNext();
1811 const SwRect& rCellB1Rect = pCellB1->getFrameArea();
1812 auto nRowHeight = rCellB1Rect.Height();
1814 // select text frame by clicking on it at the right side of the upper right cell
1815 Point ptFrom(rCellB1Rect.Left() + rCellB1Rect.Width(), rCellB1Rect.Top() + nRowHeight / 2);
1816 vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
1817 Point aFrom = rEditWin.LogicToPixel(ptFrom);
1818 MouseEvent aClickEvent(aFrom, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1819 rEditWin.MouseButtonDown(aClickEvent);
1820 rEditWin.MouseButtonUp(aClickEvent);
1822 // Then make sure that the text frame is selected:
1823 SelectionType eType = pWrtShell->GetSelectionType();
1824 CPPUNIT_ASSERT_EQUAL(SelectionType::Frame, eType);
1826 // remove selection
1827 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
1829 // select text frame by clicking on it at the right side of the bottom right cell
1830 auto pRow2 = pRow1->GetNext();
1831 CPPUNIT_ASSERT(pRow2->IsRowFrame());
1832 auto pCellA2 = pRow2->GetLower();
1833 CPPUNIT_ASSERT(pCellA2);
1834 auto pCellB2 = pCellA2->GetNext();
1835 CPPUNIT_ASSERT(pCellB2);
1836 const SwRect& rCellB2Rect = pCellB2->getFrameArea();
1837 auto nRow2Height = rCellB2Rect.Height();
1838 Point ptFrom2(rCellB2Rect.Left() + rCellB2Rect.Width(), rCellB2Rect.Top() + nRow2Height / 2);
1839 Point aFrom2 = rEditWin.LogicToPixel(ptFrom2);
1840 MouseEvent aClickEvent2(aFrom2, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1841 rEditWin.MouseButtonDown(aClickEvent2);
1842 rEditWin.MouseButtonUp(aClickEvent2);
1844 // Then make sure that the text frame is selected:
1845 SelectionType eType2 = pWrtShell->GetSelectionType();
1846 CPPUNIT_ASSERT_EQUAL(SelectionType::Frame, eType2);
1849 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf161426_content)
1851 createSwDoc("tdf161426.fodt");
1852 SwDoc* pDoc = getSwDoc();
1853 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1854 CPPUNIT_ASSERT(pWrtShell);
1855 // the cursor is not in the table
1856 CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
1858 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1859 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
1860 CPPUNIT_ASSERT(pPage);
1861 const SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
1862 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
1863 auto pPageFly = dynamic_cast<SwFlyAtContentFrame*>(rPageObjs[0]);
1864 CPPUNIT_ASSERT(pPageFly);
1865 auto pTable = dynamic_cast<SwTabFrame*>(pPageFly->GetLower());
1866 CPPUNIT_ASSERT(pTable);
1867 auto pRow1 = pTable->GetLower();
1868 CPPUNIT_ASSERT(pRow1->IsRowFrame());
1869 auto pCellA1 = pRow1->GetLower();
1870 CPPUNIT_ASSERT(pCellA1);
1871 auto pCellB1 = pCellA1->GetNext();
1872 const SwRect& rCellB1Rect = pCellB1->getFrameArea();
1873 auto nRowHeight = rCellB1Rect.Height();
1875 // select content of the B1 by clicking on the center of it
1876 Point ptFrom(rCellB1Rect.Left() + rCellB1Rect.Width() / 2, rCellB1Rect.Top() + nRowHeight / 2);
1877 vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
1878 Point aFrom = rEditWin.LogicToPixel(ptFrom);
1879 MouseEvent aClickEvent(aFrom, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1880 rEditWin.MouseButtonDown(aClickEvent);
1881 rEditWin.MouseButtonUp(aClickEvent);
1883 // Then make sure that the cursor in the table:
1884 SelectionType eType2 = pWrtShell->GetSelectionType();
1885 // This was false
1886 bool bCursorInTable = eType2 == (SelectionType::Text | SelectionType::Table);
1887 CPPUNIT_ASSERT(bCursorInTable);
1889 // select content of the B2 by clicking on the center of it
1890 auto pRow2 = pRow1->GetNext();
1891 CPPUNIT_ASSERT(pRow2->IsRowFrame());
1892 auto pCellA2 = pRow2->GetLower();
1893 CPPUNIT_ASSERT(pCellA2);
1894 auto pCellB2 = pCellA2->GetNext();
1895 CPPUNIT_ASSERT(pCellB2);
1896 const SwRect& rCellB2Rect = pCellB2->getFrameArea();
1897 auto nRow2Height = rCellB2Rect.Height();
1898 Point ptFrom2(rCellB2Rect.Left() + rCellB2Rect.Width() / 2,
1899 rCellB2Rect.Top() + nRow2Height / 2);
1900 Point aFrom2 = rEditWin.LogicToPixel(ptFrom2);
1901 MouseEvent aClickEvent2(aFrom2, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1902 rEditWin.MouseButtonDown(aClickEvent2);
1903 rEditWin.MouseButtonUp(aClickEvent2);
1905 // Then make sure that the cursor in the table:
1906 SelectionType eType3 = pWrtShell->GetSelectionType();
1907 // This was false
1908 bCursorInTable = eType3 == (SelectionType::Text | SelectionType::Table);
1909 CPPUNIT_ASSERT(bCursorInTable);
1911 // select content of the A2 by clicking on the center of it
1912 const SwRect& rCellA2Rect = pCellA2->getFrameArea();
1913 Point ptFrom3(rCellA2Rect.Left() + rCellA2Rect.Width() / 2,
1914 rCellA2Rect.Top() + nRow2Height / 2);
1915 Point aFrom3 = rEditWin.LogicToPixel(ptFrom3);
1916 MouseEvent aClickEvent3(aFrom3, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1917 rEditWin.MouseButtonDown(aClickEvent3);
1918 rEditWin.MouseButtonUp(aClickEvent3);
1920 // Then make sure that the cursor in the table:
1921 SelectionType eType4 = pWrtShell->GetSelectionType();
1922 // This was false
1923 bCursorInTable = eType4 == (SelectionType::Text | SelectionType::Table);
1924 CPPUNIT_ASSERT(bCursorInTable);
1926 // select content of the A1 by clicking on the center of it
1927 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1928 auto nRow1Height = rCellA1Rect.Height();
1929 Point ptFrom4(rCellA1Rect.Left() + rCellA1Rect.Width() / 2,
1930 rCellA1Rect.Top() + nRow1Height / 2);
1931 Point aFrom4 = rEditWin.LogicToPixel(ptFrom4);
1932 MouseEvent aClickEvent4(aFrom4, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1933 rEditWin.MouseButtonDown(aClickEvent4);
1934 rEditWin.MouseButtonUp(aClickEvent4);
1936 // Then make sure that the text frame is selected:
1937 SelectionType eType5 = pWrtShell->GetSelectionType();
1938 CPPUNIT_ASSERT_EQUAL(SelectionType::Graphic, eType5);
1941 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf161360)
1943 createSwDoc("tdf160842.fodt");
1944 SwDoc* pDoc = getSwDoc();
1945 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1946 CPPUNIT_ASSERT(pWrtShell);
1947 // the cursor is not in the table
1948 CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
1950 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
1951 auto pPage = dynamic_cast<SwPageFrame*>(pLayout->Lower());
1952 CPPUNIT_ASSERT(pPage);
1953 const SwSortedObjs& rPageObjs = *pPage->GetSortedObjs();
1954 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPageObjs.size());
1955 auto pPageFly = dynamic_cast<SwFlyAtContentFrame*>(rPageObjs[0]);
1956 CPPUNIT_ASSERT(pPageFly);
1957 auto pTable = dynamic_cast<SwTabFrame*>(pPageFly->GetLower());
1958 CPPUNIT_ASSERT(pTable);
1959 auto pRow1 = pTable->GetLower();
1960 CPPUNIT_ASSERT(pRow1->IsRowFrame());
1961 auto pCellA1 = pRow1->GetLower();
1962 CPPUNIT_ASSERT(pCellA1);
1963 const SwRect& rCellA1Rect = pCellA1->getFrameArea();
1964 auto nRowHeight = rCellA1Rect.Height();
1966 // select image by clicking on it at the center of the upper cell
1967 Point ptFrom(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + nRowHeight / 2);
1968 vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
1969 Point aFrom = rEditWin.LogicToPixel(ptFrom);
1970 MouseEvent aClickEvent(aFrom, 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
1971 rEditWin.MouseButtonDown(aClickEvent);
1972 rEditWin.MouseButtonUp(aClickEvent);
1974 // Then make sure that the image is selected:
1975 SelectionType eType = pWrtShell->GetSelectionType();
1976 CPPUNIT_ASSERT_EQUAL(SelectionType::Graphic, eType);
1978 // select the text frame instead of the image
1979 // by pressing Escape
1980 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
1982 // Then make sure that the cursor in the table:
1983 SelectionType eType2 = pWrtShell->GetSelectionType();
1984 // This was false (only SelectionType::Text)
1985 bool bCursorInTable = eType2 == (SelectionType::Text | SelectionType::Table);
1986 CPPUNIT_ASSERT(bCursorInTable);
1988 // select the text frame by pressing Escape again
1989 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
1991 eType2 = pWrtShell->GetSelectionType();
1992 CPPUNIT_ASSERT_EQUAL(SelectionType::Frame, eType2);
1994 // deselect the text frame by pressing Escape again
1995 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
1997 eType2 = pWrtShell->GetSelectionType();
1998 // The text cursor is after the floating table
1999 CPPUNIT_ASSERT_EQUAL(SelectionType::Text, eType2);
2002 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157533)
2004 // load a table with objects positioned at beginning of text lines
2005 createSwDoc("tdf157533.fodt");
2006 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2007 CPPUNIT_ASSERT(pWrtShell);
2008 auto pShell = getSwDocShell()->GetFEShell();
2009 CPPUNIT_ASSERT(pShell);
2011 auto xModel = mxComponent.queryThrow<frame::XModel>();
2012 uno::Reference<drawing::XShape> xShape(getShapeByName(u"Objet2"));
2013 uno::Reference<view::XSelectionSupplier> xCtrl(xModel->getCurrentController(), uno::UNO_QUERY);
2014 xCtrl->select(uno::Any(xShape));
2016 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
2018 // Then make sure that the cursor in the table:
2019 SelectionType eType2 = pWrtShell->GetSelectionType();
2020 // This was false (only SelectionType::Text)
2021 bool bCursorInTable = eType2 == (SelectionType::Text | SelectionType::Table);
2022 CPPUNIT_ASSERT(bCursorInTable);
2024 SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
2025 // This was false (not in the same paragraph and cell)
2026 CPPUNIT_ASSERT(pTextNode->GetText().indexOf("and the second formula") > -1);
2028 uno::Reference<drawing::XShape> xShape2(getShapeByName(u"Objet11"));
2029 xCtrl->select(uno::Any(xShape2));
2031 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
2033 SwTextNode* pTextNode2 = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
2034 // This was false (lost text cursor inside the frame of the formula)
2035 CPPUNIT_ASSERT(pTextNode2->GetTableBox());
2036 SwTableNode* pTableNode = pWrtShell->GetCursor()->GetPointNode().FindTableNode();
2037 SwTable& rTable = pTableNode->GetTable();
2038 // cursor in the same cell
2039 bool bSameBox = pTextNode2->GetTableBox() == rTable.GetTableBox(u"A1"_ustr);
2040 CPPUNIT_ASSERT(bSameBox);
2042 uno::Reference<drawing::XShape> xShape3(getShapeByName(u"Objet10"));
2043 xCtrl->select(uno::Any(xShape3));
2045 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
2047 SwTextNode* pTextNode3 = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
2048 // This was false (lost text cursor inside the frame of the formula)
2049 CPPUNIT_ASSERT(pTextNode3->GetTableBox());
2050 // cursor in the same cell
2051 bSameBox = pTextNode3->GetTableBox() == rTable.GetTableBox(u"B1"_ustr);
2052 CPPUNIT_ASSERT(bSameBox);
2055 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf115132)
2057 createSwDoc();
2058 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2059 CPPUNIT_ASSERT(pWrtShell);
2061 std::vector<OUString> vTestTableNames;
2063 // Create an empty paragraph that will separate first table from the rest
2064 pWrtShell->SplitNode();
2065 pWrtShell->StartOfSection();
2066 // Create a table at the start of document body
2067 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
2068 const SwTable* pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
2069 const SwTableFormat* pFormat = pTable->GetFrameFormat();
2070 CPPUNIT_ASSERT(pFormat);
2071 vTestTableNames.push_back(pFormat->GetName());
2072 pWrtShell->EndOfSection();
2073 // Create a table after a paragraph
2074 pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
2075 pFormat = pTable->GetFrameFormat();
2076 CPPUNIT_ASSERT(pFormat);
2077 vTestTableNames.push_back(pFormat->GetName());
2078 // Create a table immediately after the previous
2079 pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
2080 pFormat = pTable->GetFrameFormat();
2081 CPPUNIT_ASSERT(pFormat);
2082 vTestTableNames.push_back(pFormat->GetName());
2083 // Create a nested table in the middle of last row
2084 pWrtShell->GotoTable(vTestTableNames.back());
2085 for (int i = 0; i < 4; ++i)
2086 pWrtShell->GoNextCell(false);
2087 pTable = &pWrtShell->InsertTable(TableOpt, 2, 3);
2088 pFormat = pTable->GetFrameFormat();
2089 CPPUNIT_ASSERT(pFormat);
2090 vTestTableNames.push_back(pFormat->GetName());
2092 // Now check that in any cell in all tables we don't go out of a cell
2093 // using Delete or Backspace. We test cases when a table is the first node;
2094 // when we are in a first/middle/last cell in a row; when there's a paragraph
2095 // before/after this cell; when there's another table before/after this cell;
2096 // in nested table.
2097 for (const auto& rTableName : vTestTableNames)
2099 pWrtShell->GotoTable(rTableName);
2102 const SwStartNode* pNd = pWrtShell->GetCursor()->GetPointNode().FindTableBoxStartNode();
2103 pWrtShell->DelRight();
2104 CPPUNIT_ASSERT_EQUAL(pNd,
2105 pWrtShell->GetCursor()->GetPointNode().FindTableBoxStartNode());
2106 pWrtShell->DelLeft();
2107 CPPUNIT_ASSERT_EQUAL(pNd,
2108 pWrtShell->GetCursor()->GetPointNode().FindTableBoxStartNode());
2109 } while (pWrtShell->GoNextCell(false));
2113 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testXDrawPagesSupplier)
2115 createSwDoc();
2116 uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY);
2117 CPPUNIT_ASSERT_MESSAGE("XDrawPagesSupplier interface is unavailable", xDrawPagesSupplier.is());
2118 uno::Reference<drawing::XDrawPages> xDrawPages = xDrawPagesSupplier->getDrawPages();
2119 CPPUNIT_ASSERT(xDrawPages.is());
2120 CPPUNIT_ASSERT_EQUAL_MESSAGE("There must be only a single DrawPage in Writer documents",
2121 sal_Int32(1), xDrawPages->getCount());
2122 uno::Any aDrawPage = xDrawPages->getByIndex(0);
2123 uno::Reference<drawing::XDrawPage> xDrawPageFromXDrawPages(aDrawPage, uno::UNO_QUERY);
2124 CPPUNIT_ASSERT(xDrawPageFromXDrawPages.is());
2126 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
2127 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
2128 CPPUNIT_ASSERT_EQUAL_MESSAGE(
2129 "The DrawPage accessed using XDrawPages must be the same as using XDrawPageSupplier",
2130 xDrawPage.get(), xDrawPageFromXDrawPages.get());
2133 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf116403)
2135 createSwDoc("tdf116403-considerborders.odt");
2136 // Check that before ToX update, the tab stop position is the old one
2137 uno::Reference<text::XTextRange> xParagraph = getParagraph(2, u"1\t1"_ustr);
2138 auto aTabs = getProperty<uno::Sequence<style::TabStop>>(xParagraph, u"ParaTabStops"_ustr);
2139 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aTabs.getLength());
2140 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(17000), aTabs[0].Position);
2142 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2143 const SwTOXBase* pTOX = pWrtShell->GetTOX(0);
2144 CPPUNIT_ASSERT(pTOX);
2145 pWrtShell->UpdateTableOf(*pTOX);
2147 xParagraph = getParagraph(2, u"1\t1"_ustr);
2148 aTabs = getProperty<uno::Sequence<style::TabStop>>(xParagraph, u"ParaTabStops"_ustr);
2149 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(1), aTabs.getLength());
2150 // This was still 17000, refreshing ToX didn't take borders spacings and widths into account
2151 CPPUNIT_ASSERT_EQUAL_MESSAGE("Page borders must be considered for right-aligned tabstop",
2152 static_cast<sal_Int32>(17000 - 2 * 500 - 2 * 1 - 1),
2153 aTabs[0].Position);
2156 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testHtmlCopyImages)
2158 // Load a document with an image.
2159 createSwDoc("image.odt");
2160 SwDoc* pDoc = getSwDoc();
2162 // Trigger the copy part of HTML copy&paste.
2163 WriterRef xWrt = new SwHTMLWriter(/*rBaseURL=*/OUString());
2164 CPPUNIT_ASSERT(xWrt.is());
2166 xWrt->m_bWriteClipboardDoc = true;
2167 xWrt->m_bWriteOnlyFirstTable = false;
2168 xWrt->SetShowProgress(false);
2170 SvFileStream aStream(maTempFile.GetURL(), StreamMode::WRITE | StreamMode::TRUNC);
2171 SwWriter aWrt(aStream, *pDoc);
2172 aWrt.Write(xWrt);
2174 htmlDocUniquePtr pHtmlDoc = parseHtml(maTempFile);
2175 CPPUNIT_ASSERT(pHtmlDoc);
2177 // This failed, image was lost during HTML copy.
2178 OUString aImage = getXPath(pHtmlDoc, "/html/body/p/img", "src");
2179 // Also make sure that the image is not embedded (e.g. Word doesn't handle
2180 // embedded images).
2181 CPPUNIT_ASSERT(aImage.startsWith("file:///"));
2184 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf116789)
2186 createSwDoc("tdf116789.fodt");
2187 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
2188 uno::Reference<text::XText> xText1;
2189 uno::Reference<text::XText> xText2;
2191 uno::Reference<text::XTextContent> xBookmark(
2192 xBookmarksSupplier->getBookmarks()->getByName(u"Bookmark 1"_ustr), uno::UNO_QUERY);
2193 xText1 = xBookmark->getAnchor()->getText();
2196 uno::Reference<text::XTextContent> xBookmark(
2197 xBookmarksSupplier->getBookmarks()->getByName(u"Bookmark 1"_ustr), uno::UNO_QUERY);
2198 xText2 = xBookmark->getAnchor()->getText();
2200 // This failed, we got two different SwXCell for the same bookmark anchor text.
2201 CPPUNIT_ASSERT_EQUAL(xText1, xText2);
2204 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf91801)
2206 // Tests calculation with several user field variables without prior user fields
2207 createSwDoc("tdf91801.fodt");
2208 uno::Reference<text::XTextTable> xTable(getParagraphOrTable(1), uno::UNO_QUERY);
2209 uno::Reference<table::XCell> xCell(xTable->getCellByName(u"A1"_ustr));
2210 CPPUNIT_ASSERT_EQUAL(555.0, xCell->getValue());
2213 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf51223)
2215 createSwDoc();
2216 SwDoc* pDoc = getSwDoc();
2217 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2218 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
2219 SwNodeOffset nIndex = pWrtShell->GetCursor()->GetPointNode().GetIndex();
2220 pWrtShell->Insert(u"i"_ustr);
2221 pWrtShell->SplitNode(true);
2222 CPPUNIT_ASSERT_EQUAL(u"I"_ustr, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
2223 rUndoManager.Undo();
2224 CPPUNIT_ASSERT_EQUAL(u"i"_ustr, static_cast<SwTextNode*>(pDoc->GetNodes()[nIndex])->GetText());
2227 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testFontEmbedding)
2229 #if HAVE_MORE_FONTS && !defined(MACOSX)
2230 createSwDoc("testFontEmbedding.odt");
2232 OString aContentBaseXpath("/office:document-content/office:font-face-decls"_ostr);
2233 OString aSettingsBaseXpath(
2234 "/office:document-settings/office:settings/config:config-item-set"_ostr);
2236 xmlDocUniquePtr pXmlDoc;
2238 // Get document settings
2239 uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY_THROW);
2240 uno::Reference<beans::XPropertySet> xProps(
2241 xFactory->createInstance(u"com.sun.star.document.Settings"_ustr), uno::UNO_QUERY_THROW);
2243 // Check font embedding state
2244 CPPUNIT_ASSERT_EQUAL(false, xProps->getPropertyValue(u"EmbedFonts"_ustr).get<bool>());
2245 CPPUNIT_ASSERT_EQUAL(false, xProps->getPropertyValue(u"EmbedOnlyUsedFonts"_ustr).get<bool>());
2246 // Font scripts should be enabled by default, however this has no effect unless "EmbedOnlyUsedFonts" is enabled
2247 CPPUNIT_ASSERT_EQUAL(true, xProps->getPropertyValue(u"EmbedLatinScriptFonts"_ustr).get<bool>());
2248 CPPUNIT_ASSERT_EQUAL(true, xProps->getPropertyValue(u"EmbedAsianScriptFonts"_ustr).get<bool>());
2249 CPPUNIT_ASSERT_EQUAL(true,
2250 xProps->getPropertyValue(u"EmbedComplexScriptFonts"_ustr).get<bool>());
2252 // CASE 1 - no font embedding enabled
2254 // Save the document
2255 save(u"writer8"_ustr);
2256 CPPUNIT_ASSERT(maTempFile.IsValid());
2258 // Check setting - No font embedding should be enabled
2259 pXmlDoc = parseExport(u"settings.xml"_ustr);
2260 CPPUNIT_ASSERT(pXmlDoc);
2261 assertXPathContent(
2262 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedFonts']", u"false");
2264 // Check content - No font-face-src nodes should be present
2265 pXmlDoc = parseExport(u"content.xml"_ustr);
2266 CPPUNIT_ASSERT(pXmlDoc);
2268 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6);
2269 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']");
2270 assertXPath(
2271 pXmlDoc,
2272 aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 0);
2273 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']");
2274 assertXPath(pXmlDoc,
2275 aContentBaseXpath
2276 + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src",
2278 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']");
2279 assertXPath(pXmlDoc,
2280 aContentBaseXpath
2281 + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src",
2283 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']");
2284 assertXPath(pXmlDoc,
2285 aContentBaseXpath
2286 + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src",
2288 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']");
2289 assertXPath(pXmlDoc,
2290 aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 0);
2291 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']");
2292 assertXPath(pXmlDoc,
2293 aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 0);
2295 // CASE 2 - font embedding enabled, but embed used fonts disabled
2297 // Enable font embedding, disable embedding used font only
2298 xProps->setPropertyValue(u"EmbedFonts"_ustr, uno::Any(true));
2299 xProps->setPropertyValue(u"EmbedOnlyUsedFonts"_ustr, uno::Any(false));
2301 // Save the document again
2302 save(u"writer8"_ustr);
2303 CPPUNIT_ASSERT(maTempFile.IsValid());
2305 // Check setting - font embedding should be enabled + embed only used fonts and scripts
2306 pXmlDoc = parseExport(u"settings.xml"_ustr);
2307 CPPUNIT_ASSERT(pXmlDoc);
2308 assertXPathContent(
2309 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedFonts']", u"true");
2310 assertXPathContent(
2311 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedOnlyUsedFonts']",
2312 u"false");
2313 assertXPathContent(
2314 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedLatinScriptFonts']",
2315 u"true");
2316 assertXPathContent(
2317 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedAsianScriptFonts']",
2318 u"true");
2319 assertXPathContent(
2320 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedComplexScriptFonts']",
2321 u"true");
2323 // Check content - font-face-src should be present only for "Liberation Sans" fonts
2325 pXmlDoc = parseExport(u"content.xml"_ustr);
2326 CPPUNIT_ASSERT(pXmlDoc);
2328 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6);
2329 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']");
2330 assertXPath(
2331 pXmlDoc,
2332 aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 1);
2333 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']");
2334 assertXPath(pXmlDoc,
2335 aContentBaseXpath
2336 + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src",
2338 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']");
2339 assertXPath(pXmlDoc,
2340 aContentBaseXpath
2341 + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src",
2343 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']");
2344 assertXPath(pXmlDoc,
2345 aContentBaseXpath
2346 + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src",
2348 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']");
2349 assertXPath(pXmlDoc,
2350 aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 1);
2351 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']");
2352 assertXPath(pXmlDoc,
2353 aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 1);
2355 // CASE 3 - font embedding enabled, embed only used fonts enabled
2357 // Enable font embedding and setting to embed used fonts only
2358 xProps->setPropertyValue(u"EmbedFonts"_ustr, uno::Any(true));
2359 xProps->setPropertyValue(u"EmbedOnlyUsedFonts"_ustr, uno::Any(true));
2360 xProps->setPropertyValue(u"EmbedLatinScriptFonts"_ustr, uno::Any(true));
2361 xProps->setPropertyValue(u"EmbedAsianScriptFonts"_ustr, uno::Any(true));
2362 xProps->setPropertyValue(u"EmbedComplexScriptFonts"_ustr, uno::Any(true));
2364 // Save the document again
2365 save(u"writer8"_ustr);
2366 CPPUNIT_ASSERT(maTempFile.IsValid());
2368 // Check setting - font embedding should be enabled + embed only used fonts and scripts
2369 pXmlDoc = parseExport(u"settings.xml"_ustr);
2370 CPPUNIT_ASSERT(pXmlDoc);
2371 assertXPathContent(
2372 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedFonts']", u"true");
2373 assertXPathContent(
2374 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedOnlyUsedFonts']",
2375 u"true");
2376 assertXPathContent(
2377 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedLatinScriptFonts']",
2378 u"true");
2379 assertXPathContent(
2380 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedAsianScriptFonts']",
2381 u"true");
2382 assertXPathContent(
2383 pXmlDoc, aSettingsBaseXpath + "/config:config-item[@config:name='EmbedComplexScriptFonts']",
2384 u"true");
2386 // Check content - font-face-src should be present only for "Liberation Sans" fonts
2388 pXmlDoc = parseExport(u"content.xml"_ustr);
2389 CPPUNIT_ASSERT(pXmlDoc);
2391 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face", 6);
2392 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']");
2393 assertXPath(
2394 pXmlDoc,
2395 aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans']/svg:font-face-src", 0);
2396 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Sans1']");
2397 assertXPath(pXmlDoc,
2398 aContentBaseXpath
2399 + "/style:font-face[@style:name='Liberation Sans1']/svg:font-face-src",
2401 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif']");
2402 assertXPath(pXmlDoc,
2403 aContentBaseXpath
2404 + "/style:font-face[@style:name='Liberation Serif']/svg:font-face-src",
2406 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Liberation Serif1']");
2407 assertXPath(pXmlDoc,
2408 aContentBaseXpath
2409 + "/style:font-face[@style:name='Liberation Serif1']/svg:font-face-src",
2411 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Carlito']");
2412 assertXPath(pXmlDoc,
2413 aContentBaseXpath + "/style:font-face[@style:name='Carlito']/svg:font-face-src", 1);
2414 assertXPath(pXmlDoc, aContentBaseXpath + "/style:font-face[@style:name='Caladea']");
2415 assertXPath(pXmlDoc,
2416 aContentBaseXpath + "/style:font-face[@style:name='Caladea']/svg:font-face-src", 0);
2417 #endif
2420 // Unit test for fix inconsistent bookmark behavior around at-char/as-char anchored frames
2422 // We have a placeholder character in the sw doc model for as-char anchored frames,
2423 // so it's possible to have a bookmark before/after the frame or a non-collapsed bookmark
2424 // which covers the frame. The same is not true for at-char anchored frames,
2425 // where the anchor points to a doc model position, but there is no placeholder character.
2426 // If a bookmark is created covering the start and end of the anchor of the frame,
2427 // internally we create a collapsed bookmark which has the same position as the anchor of the frame.
2428 // When this doc model is handled by SwXParagraph::createEnumeration(),
2429 // first the frame and then the bookmark is appended to the text portion enumeration,
2430 // so your bookmark around the frame is turned into a collapsed bookmark after the frame.
2431 // (The same happens when we roundtrip an ODT document representing this doc model.)
2433 // Fix the problem by inserting collapsed bookmarks with affected anchor positions
2434 // (same position is the anchor for an at-char frame) into the enumeration in two stages:
2435 // first the start of them before frames and then the end of them + other bookmarks.
2436 // This way UNO API users get their non-collapsed bookmarks around at-char anchored frames,
2437 // similar to as-char ones.
2438 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testInconsistentBookmark)
2440 // create test document with text and bookmark
2442 createSwDoc("testInconsistentBookmark.ott");
2443 SwDoc* pDoc = getSwDoc();
2444 IDocumentMarkAccess& rIDMA(*pDoc->getIDocumentMarkAccess());
2445 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
2446 SwCursor aPaM(SwPosition(aIdx), nullptr);
2447 aPaM.SetMark();
2448 aPaM.MovePara(GoCurrPara, fnParaStart);
2449 aPaM.MovePara(GoCurrPara, fnParaEnd);
2450 rIDMA.makeMark(aPaM, u"Mark"_ustr, IDocumentMarkAccess::MarkType::BOOKMARK,
2451 ::sw::mark::InsertMode::New);
2452 aPaM.Exchange();
2453 aPaM.DeleteMark();
2456 // save document and verify the bookmark scoup
2458 // save document
2459 save(u"writer8"_ustr);
2461 // load only content.xml
2462 xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
2463 static constexpr const char* aPath(
2464 "/office:document-content/office:body/office:text/text:p");
2466 const int pos1 = getXPathPosition(pXmlDoc, aPath, "bookmark-start");
2467 const int pos2 = getXPathPosition(pXmlDoc, aPath, "control");
2468 const int pos3 = getXPathPosition(pXmlDoc, aPath, "bookmark-end");
2470 CPPUNIT_ASSERT_GREATER(pos1, pos2);
2471 CPPUNIT_ASSERT_GREATER(pos2, pos3);
2475 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSpellOnlineParameter)
2477 createSwDoc();
2478 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2479 const SwViewOption* pOpt = pWrtShell->GetViewOptions();
2480 bool bSet = pOpt->IsOnlineSpell();
2482 uno::Sequence<beans::PropertyValue> params
2483 = comphelper::InitPropertySequence({ { "Enable", uno::Any(!bSet) } });
2484 dispatchCommand(mxComponent, u".uno:SpellOnline"_ustr, params);
2485 CPPUNIT_ASSERT_EQUAL(!bSet, pOpt->IsOnlineSpell());
2487 // set the same state as now and we don't expect any change (no-toggle)
2488 params = comphelper::InitPropertySequence({ { "Enable", uno::Any(!bSet) } });
2489 dispatchCommand(mxComponent, u".uno:SpellOnline"_ustr, params);
2490 CPPUNIT_ASSERT_EQUAL(!bSet, pOpt->IsOnlineSpell());
2493 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf124603)
2495 createSwDoc();
2496 SwDoc* pDoc = getSwDoc();
2497 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2498 const SwViewOption* pOpt = pWrtShell->GetViewOptions();
2499 uno::Sequence<beans::PropertyValue> params
2500 = comphelper::InitPropertySequence({ { "Enable", uno::Any(true) } });
2501 dispatchCommand(mxComponent, u".uno:SpellOnline"_ustr, params);
2503 // Automatic Spell Checking is enabled
2505 CPPUNIT_ASSERT(pOpt->IsOnlineSpell());
2507 // check available en_US dictionary and test spelling with it
2508 uno::Reference<XLinguServiceManager2> xLngSvcMgr(GetLngSvcMgr_Impl());
2509 uno::Reference<XSpellChecker1> xSpell;
2510 xSpell.set(xLngSvcMgr->getSpellChecker(), UNO_QUERY);
2511 LanguageType eLang
2512 = LanguageTag::convertToLanguageType(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()));
2513 if (xSpell.is() && xSpell->hasLanguage(static_cast<sal_uInt16>(eLang)))
2515 // Type a correct word
2517 emulateTyping(u"the ");
2518 SwCursorShell* pShell(pDoc->GetEditShell());
2519 CPPUNIT_ASSERT(pShell);
2520 SwTextNode* pNode = pShell->GetCursor()->GetPointNode().GetTextNode();
2521 // no bad word
2522 CPPUNIT_ASSERT_EQUAL(static_cast<SwWrongList*>(nullptr), pNode->GetWrong());
2524 // Create a bad word from the good: "the" -> "thex"
2526 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
2527 emulateTyping(u"x");
2528 // tdf#92036 pending spell checking
2529 bool bPending = !pNode->GetWrong() || !pNode->GetWrong()->Count();
2530 CPPUNIT_ASSERT(bPending);
2532 // Move right, leave the bad word - since the fix for tdf#136294, this triggers the check
2534 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
2535 Scheduler::ProcessEventsToIdle();
2536 CPPUNIT_ASSERT(pNode->GetWrong());
2537 // This was 0 (pending spell checking)
2538 CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pNode->GetWrong()->Count());
2542 #if !defined(MACOSX)
2543 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf45949)
2545 createSwDoc();
2546 SwDoc* pDoc = getSwDoc();
2547 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2548 const SwViewOption* pOpt = pWrtShell->GetViewOptions();
2549 uno::Sequence<beans::PropertyValue> params
2550 = comphelper::InitPropertySequence({ { "Enable", uno::Any(true) } });
2551 dispatchCommand(mxComponent, u".uno:SpellOnline"_ustr, params);
2553 // Automatic Spell Checking is enabled
2554 CPPUNIT_ASSERT(pOpt->IsOnlineSpell());
2556 // check available en_US dictionary and test spelling with it
2557 uno::Reference<XLinguServiceManager2> xLngSvcMgr(GetLngSvcMgr_Impl());
2558 uno::Reference<XSpellChecker1> xSpell;
2559 xSpell.set(xLngSvcMgr->getSpellChecker(), UNO_QUERY);
2560 LanguageType eLang
2561 = LanguageTag::convertToLanguageType(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()));
2562 if (xSpell.is() && xSpell->hasLanguage(static_cast<sal_uInt16>(eLang)))
2564 emulateTyping(u"baaad http://www.baaad.org baaad");
2565 SwCursorShell* pShell(pDoc->GetEditShell());
2566 CPPUNIT_ASSERT(pShell);
2567 SwTextNode* pNode = pShell->GetCursor()->GetPointNode().GetTextNode();
2569 // tdf#152492: Without the fix in place, this test would have failed with
2570 // - Expected: 1
2571 // - Actual : 3
2572 CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pNode->GetWrong()->Count());
2574 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 10, /*bBasicCall=*/false);
2575 emulateTyping(u" ");
2577 CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), pNode->GetWrong()->Count());
2579 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 6, /*bBasicCall=*/false);
2580 emulateTyping(u" ");
2582 // Move down to trigger spell checking
2583 pWrtShell->Down(/*bSelect=*/false, 1);
2584 Scheduler::ProcessEventsToIdle();
2586 // Without the fix in place, this test would have failed with
2587 // - Expected: 3
2588 // - Actual : 2
2589 CPPUNIT_ASSERT_EQUAL(sal_uInt16(3), pNode->GetWrong()->Count());
2592 #endif
2594 #if !defined(MACOSX)
2595 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157442)
2597 createSwDoc();
2598 SwDoc* pDoc = getSwDoc();
2599 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2600 const SwViewOption* pOpt = pWrtShell->GetViewOptions();
2601 uno::Sequence<beans::PropertyValue> params
2602 = comphelper::InitPropertySequence({ { "Enable", uno::Any(true) } });
2603 dispatchCommand(mxComponent, u".uno:SpellOnline"_ustr, params);
2605 // Automatic Spell Checking is enabled
2606 CPPUNIT_ASSERT(pOpt->IsOnlineSpell());
2608 // check available en_US dictionary and test spelling with it
2609 uno::Reference<XLinguServiceManager2> xLngSvcMgr(GetLngSvcMgr_Impl());
2610 uno::Reference<XSpellChecker1> xSpell;
2611 xSpell.set(xLngSvcMgr->getSpellChecker(), UNO_QUERY);
2612 LanguageType eLang
2613 = LanguageTag::convertToLanguageType(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()));
2614 if (xSpell.is() && xSpell->hasLanguage(static_cast<sal_uInt16>(eLang)))
2616 uno::Reference<linguistic2::XLinguProperties> xLinguProperties(
2617 LinguMgr::GetLinguPropertySet());
2619 // Spell with digits is disabled by default
2620 CPPUNIT_ASSERT_EQUAL(sal_False, xLinguProperties->getIsSpellWithDigits());
2622 emulateTyping(u"ErrorError Treee2 ");
2623 SwCursorShell* pShell(pDoc->GetEditShell());
2624 CPPUNIT_ASSERT(pShell);
2625 SwTextNode* pNode = pShell->GetCursor()->GetPointNode().GetTextNode();
2627 // Without the fix in place, this test would have crashed because GetWrong() returns nullptr
2628 CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pNode->GetWrong()->Count());
2631 #endif
2633 #if !defined(MACOSX)
2634 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf65535)
2636 createSwDoc("tdf65535.fodt");
2637 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2638 const SwViewOption* pOpt = pWrtShell->GetViewOptions();
2639 uno::Sequence<beans::PropertyValue> params
2640 = comphelper::InitPropertySequence({ { "Enable", uno::Any(true) } });
2641 dispatchCommand(mxComponent, u".uno:SpellOnline"_ustr, params);
2643 // Automatic Spell Checking is enabled
2645 CPPUNIT_ASSERT(pOpt->IsOnlineSpell());
2647 // check available en_US dictionary and test spelling with it
2648 uno::Reference<XLinguServiceManager2> xLngSvcMgr(GetLngSvcMgr_Impl());
2649 uno::Reference<XSpellChecker1> xSpell;
2650 xSpell.set(xLngSvcMgr->getSpellChecker(), UNO_QUERY);
2651 LanguageType eLang
2652 = LanguageTag::convertToLanguageType(lang::Locale(u"en"_ustr, u"US"_ustr, OUString()));
2653 if (xSpell.is() && xSpell->hasLanguage(static_cast<sal_uInt16>(eLang)))
2655 // trigger online spell checking by (a few) spaces to be sure to get it
2657 emulateTyping(u" ");
2659 // FIXME: inserting a space before the bad word removes the red underline
2660 // Insert a second space to get the red underline (back)
2662 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
2663 emulateTyping(u" ");
2665 // Select the bad word (right to left, as during right click)
2667 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 5, /*bBasicCall=*/false);
2668 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 4, /*bBasicCall=*/false);
2670 // choose the word "Baaed" from the spelling suggestions of the context menu
2672 SfxViewShell* pViewShell = SfxViewShell::Current();
2673 CPPUNIT_ASSERT(pViewShell);
2675 static constexpr OUStringLiteral sApplyRule(u"Spelling_Baaed");
2676 SfxStringItem aApplyItem(FN_PARAM_1, sApplyRule);
2677 pViewShell->GetViewFrame().GetDispatcher()->ExecuteList(
2678 SID_SPELLCHECK_APPLY_SUGGESTION, SfxCallMode::SYNCHRON, { &aApplyItem });
2681 // check the replacement in the text
2683 CPPUNIT_ASSERT_EQUAL(u" Baaed"_ustr, getParagraph(1)->getString());
2686 // check the remaining comment
2688 tools::JsonWriter aJsonWriter;
2689 SwXTextDocument* pTextDoc = getSwTextDoc();
2690 pTextDoc->getPostIts(aJsonWriter);
2691 OString pChar = aJsonWriter.finishAndGetAsOString();
2692 std::stringstream aStream((std::string(pChar)));
2693 boost::property_tree::ptree aTree;
2694 boost::property_tree::read_json(aStream, aTree);
2695 OString sCommentText;
2696 for (const boost::property_tree::ptree::value_type& rValue : aTree.get_child("comments"))
2698 const boost::property_tree::ptree& rComment = rValue.second;
2699 sCommentText = OString(rComment.get<std::string>("html"));
2701 // This was false (lost comment with spelling replacement)
2702 CPPUNIT_ASSERT_EQUAL("<div>with comment</div>"_ostr, sCommentText);
2704 #endif
2706 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testRedlineAutoCorrect)
2708 createSwDoc("redline-autocorrect.fodt");
2709 SwDoc* pDoc = getSwDoc();
2711 dispatchCommand(mxComponent, u".uno:GoToEndOfDoc"_ustr, {});
2713 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2714 CPPUNIT_ASSERT(pWrtShell);
2716 // show tracked deletion with enabled change tracking
2717 RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
2718 CPPUNIT_ASSERT(nMode & (RedlineFlags::ShowDelete | RedlineFlags::ShowInsert));
2719 pWrtShell->SetRedlineFlags(nMode);
2720 CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);
2722 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
2723 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
2725 emulateTyping(u" ");
2727 // tdf#83419 This was "Ts " removing the deletion of "t" silently by sentence capitalization
2728 OUString sReplaced(u"ts "_ustr);
2729 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2731 // hide delete redlines
2732 pWrtShell->SetRedlineFlags(nMode & ~RedlineFlags::ShowDelete);
2734 // repeat it with not visible redlining
2735 dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
2737 emulateTyping(u" ");
2739 sReplaced = "S ";
2740 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2742 // show delete redlines
2743 pWrtShell->SetRedlineFlags(nMode);
2745 // This still keep the tracked deletion, capitalize only the visible text "s"
2746 // with tracked deletion of the original character
2747 sReplaced = "tsS ";
2748 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2750 // repeat it with visible redlining and word auto replacement of "tset"
2751 dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
2752 dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
2754 emulateTyping(u"et ");
2755 // This was "Ttest" removing the tracked deletion silently.
2756 // Don't replace, if a redline starts or ends within the text.
2757 sReplaced = "tset ";
2758 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2760 // Otherwise replace it
2761 emulateTyping(u"tset ");
2762 sReplaced = "tset test ";
2763 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2765 // Including capitalization
2766 emulateTyping(u"end. word ");
2767 sReplaced = "tset test end. Word ";
2768 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2770 // tracked deletions after the correction point doesn't affect autocorrect
2771 dispatchCommand(mxComponent, u".uno:GoToStartOfDoc"_ustr, {});
2772 emulateTyping(u"a ");
2773 sReplaced = "A tset test end. Word ";
2774 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2777 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testRedlineAutoCorrect2)
2779 createSwDoc("redline-autocorrect2.fodt");
2780 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2781 CPPUNIT_ASSERT(pWrtShell);
2783 dispatchCommand(mxComponent, u".uno:GoToEndOfDoc"_ustr, {});
2785 // show tracked deletion
2786 RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
2787 CPPUNIT_ASSERT(nMode & (RedlineFlags::ShowDelete | RedlineFlags::ShowInsert));
2788 pWrtShell->SetRedlineFlags(nMode);
2789 CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);
2791 emulateTyping(u"... ");
2793 // This was "LoremLorem,…," (duplicating the deleted comma, but without deletion)
2794 // Don't replace, if a redline starts or ends within the text.
2795 OUString sReplaced = u"Lorem,... "_ustr;
2796 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2798 // Continue it:
2799 emulateTyping(u"Lorem,... ");
2800 sReplaced = u"Lorem,... Lorem,… "_ustr;
2801 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2804 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testEmojiAutoCorrect)
2806 createSwDoc("redline-autocorrect3.fodt");
2807 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2808 CPPUNIT_ASSERT(pWrtShell);
2810 // Emoji replacement (:snowman: -> ☃)
2812 // without change tracking
2813 CPPUNIT_ASSERT(!(pWrtShell->GetRedlineFlags() & RedlineFlags::On));
2814 emulateTyping(u":snowman:");
2815 OUString sReplaced = u"☃Lorem,"_ustr;
2816 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2818 // with change tracking (showing redlines)
2819 RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
2820 CPPUNIT_ASSERT(nMode & (RedlineFlags::ShowDelete | RedlineFlags::ShowInsert));
2821 pWrtShell->SetRedlineFlags(nMode);
2822 CPPUNIT_ASSERT(nMode & RedlineFlags::On);
2823 CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);
2825 emulateTyping(u":snowman:");
2826 sReplaced = u"☃☃Lorem,"_ustr;
2828 // tdf#140674 This was ":snowman:" instead of autocorrect
2829 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2832 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf153423)
2834 createSwDoc();
2835 SvxSwAutoFormatFlags flags(*SwEditShell::GetAutoFormatFlags());
2836 comphelper::ScopeGuard const g([=]() { SwEditShell::SetAutoFormatFlags(&flags); });
2837 flags.bSetNumRule = true;
2838 SwEditShell::SetAutoFormatFlags(&flags);
2840 emulateTyping(u"1. Item 1");
2842 SwXTextDocument* pTextDoc = getSwTextDoc();
2843 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RETURN);
2844 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_RETURN);
2845 Scheduler::ProcessEventsToIdle();
2847 // Without the fix in place, this test would have failed with
2848 // - Expected: 1.
2849 // - Actual : 10.
2850 CPPUNIT_ASSERT_EQUAL(u"1."_ustr,
2851 getProperty<OUString>(getParagraph(1), u"ListLabelString"_ustr));
2854 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf133589)
2856 // Hungarian test document with right-to-left paragraph setting
2857 createSwDoc("tdf133589.fodt");
2858 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2859 CPPUNIT_ASSERT(pWrtShell);
2860 // translitere words to Old Hungarian
2861 emulateTyping(u"székely ");
2862 OUString sReplaced(u"𐳥𐳋𐳓𐳉𐳗 "_ustr);
2863 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2864 // disambiguate consonants: asszony -> asz|szony
2865 emulateTyping(u"asszony ");
2866 sReplaced += u"𐳀𐳥𐳥𐳛𐳚 ";
2867 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2868 // disambiguate consonants: kosszarv -> kos|szarv
2869 // (add explicit ZWSP temporarily for consonant disambiguation, because the requested
2870 // hu_HU hyphenation dictionary isn't installed on all testing platform)
2871 // pWrtShell->Insert(u"kosszarv");
2872 emulateTyping(u"kos\u200Bszarv ");
2873 sReplaced += u"𐳓𐳛𐳤𐳥𐳀𐳢𐳮 ";
2874 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2875 // transliterate numbers to Old Hungarian
2876 emulateTyping(u"2020 ");
2877 sReplaced += u"𐳺𐳺𐳿𐳼𐳼 ";
2878 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2880 // tdf#147546 transliterate punctuation marks
2882 // question mark
2883 emulateTyping(u"Kérdőjel?");
2884 sReplaced += u"𐲓𐳋𐳢𐳇𐳟𐳒𐳉𐳖";
2885 OUString sReplaced2(sReplaced + "?");
2886 CPPUNIT_ASSERT_EQUAL(sReplaced2, getParagraph(1)->getString());
2887 emulateTyping(u" ");
2888 sReplaced += u"⸮ ";
2889 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2890 // comma
2891 emulateTyping(u"Vessző,");
2892 sReplaced += u"𐲮𐳉𐳥𐳥𐳟";
2893 sReplaced2 = sReplaced + ",";
2894 CPPUNIT_ASSERT_EQUAL(sReplaced2, getParagraph(1)->getString());
2895 emulateTyping(u" ");
2896 sReplaced += u"⹁ ";
2897 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2898 // semicolon
2899 emulateTyping(u"pontosvessző;");
2900 sReplaced += u"𐳠𐳛𐳙𐳦𐳛𐳤𐳮𐳉𐳥𐳥𐳟";
2901 sReplaced2 = sReplaced + ";";
2902 CPPUNIT_ASSERT_EQUAL(sReplaced2, getParagraph(1)->getString());
2903 emulateTyping(u" ");
2904 sReplaced += u"⁏ ";
2905 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2906 // quotation marks
2907 emulateTyping(u"„idézőjel” ");
2908 sReplaced += u"⹂𐳐𐳇𐳋𐳯𐳟𐳒𐳉𐳖‟ ";
2909 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2911 // tdf#148672 transliterate word with closing bracket
2912 emulateTyping(u"word] ");
2913 sReplaced += u"𐳮𐳛𐳢𐳇] "; // This was "word]" (no transliteration)
2914 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2916 // tdf#148672 transliterate words with parenthesis (libnumbertext 1.0.11)
2917 emulateTyping(u"(word) ");
2918 sReplaced += u"(𐳮𐳛𐳢𐳇) "; // This was "(word)" (no transliteration)
2919 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2921 emulateTyping(u"(word ");
2922 sReplaced += u"(𐳮𐳛𐳢𐳇 "; // This was "(word" (no transliteration)
2923 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2925 emulateTyping(u"word) ");
2926 sReplaced += u"𐳮𐳛𐳢𐳇) "; // This was "word)" (no transliteration)
2927 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2929 emulateTyping(u"{word} ");
2930 sReplaced += u"{𐳮𐳛𐳢𐳇} "; // This was "(word)" (no transliteration)
2931 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2933 emulateTyping(u"{word ");
2934 sReplaced += u"{𐳮𐳛𐳢𐳇 "; // This was "(word" (no transliteration)
2935 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2937 emulateTyping(u"word} ");
2938 sReplaced += u"𐳮𐳛𐳢𐳇} "; // This was "word)" (no transliteration)
2939 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2941 emulateTyping(u"[word] ");
2942 sReplaced += u"[𐳮𐳛𐳢𐳇] "; // This was "(word)" (no transliteration)
2943 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2945 emulateTyping(u"[word ");
2946 sReplaced += u"[𐳮𐳛𐳢𐳇 "; // This was "(word" (no transliteration)
2947 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
2950 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testAutoCorr)
2952 createSwDoc();
2953 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2954 CPPUNIT_ASSERT(pWrtShell);
2956 //Normal AutoCorrect
2957 emulateTyping(u"tset ");
2958 CPPUNIT_ASSERT_EQUAL(u"Test "_ustr, getParagraph(1)->getString());
2960 //AutoCorrect with change style to bolt
2961 emulateTyping(u"Bolt ");
2962 const uno::Reference<text::XTextRange> xRun = getRun(getParagraph(1), 2);
2963 CPPUNIT_ASSERT_EQUAL(u"Bolt"_ustr, xRun->getString());
2964 CPPUNIT_ASSERT_EQUAL(u"Arial"_ustr, getProperty<OUString>(xRun, u"CharFontName"_ustr));
2966 //AutoCorrect inserts Table with 2 rows and 3 columns
2967 emulateTyping(u"4xx ");
2968 const uno::Reference<text::XTextTable> xTable(getParagraphOrTable(2), uno::UNO_QUERY);
2969 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable->getRows()->getCount());
2970 CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable->getColumns()->getCount());
2973 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf130274)
2975 createSwDoc();
2976 SwDoc* pDoc = getSwDoc();
2977 SwWrtShell* const pWrtShell = getSwDocShell()->GetWrtShell();
2978 CPPUNIT_ASSERT(pWrtShell);
2980 CPPUNIT_ASSERT(!pWrtShell->GetLayout()->IsHideRedlines());
2981 CPPUNIT_ASSERT(
2982 !IDocumentRedlineAccess::IsRedlineOn(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
2984 // "tset" may be replaced by the AutoCorrect in the test profile
2985 emulateTyping(u"tset");
2986 // select from left to right
2987 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 4, /*bBasicCall=*/false);
2988 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 4, /*bBasicCall=*/false);
2990 pWrtShell->SetRedlineFlags(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
2991 // this would crash in AutoCorrect
2992 emulateTyping(u".");
2994 CPPUNIT_ASSERT(!pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty());
2997 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf83260)
2999 createSwDoc("tdf83260-1.odt");
3000 SwDoc* pDoc = getSwDoc();
3001 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
3002 CPPUNIT_ASSERT(pWrtShell);
3004 // enabled but not shown
3005 CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());
3006 #if 0
3007 CPPUNIT_ASSERT(IDocumentRedlineAccess::IsHideChanges(
3008 pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
3009 #endif
3010 CPPUNIT_ASSERT(
3011 IDocumentRedlineAccess::IsRedlineOn(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
3012 CPPUNIT_ASSERT(!pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty());
3014 // the document contains redlines that are combined with CompressRedlines()
3015 // if that happens during AutoCorrect then indexes in Undo are off -> crash
3016 emulateTyping(u"tset ");
3017 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
3018 auto const nActions(rUndoManager.GetUndoActionCount());
3019 for (auto i = nActions; 0 < i; --i)
3021 rUndoManager.Undo();
3023 // check that every text node has a layout frame
3024 for (SwNodeOffset i(0); i < pDoc->GetNodes().Count(); ++i)
3026 if (SwTextNode const* const pNode = pDoc->GetNodes()[i]->GetTextNode())
3028 CPPUNIT_ASSERT(pNode->getLayoutFrame(nullptr, nullptr, nullptr));
3031 for (auto i = nActions; 0 < i; --i)
3033 rUndoManager.Redo();
3035 for (SwNodeOffset i(0); i < pDoc->GetNodes().Count(); ++i)
3037 if (SwTextNode const* const pNode = pDoc->GetNodes()[i]->GetTextNode())
3039 CPPUNIT_ASSERT(pNode->getLayoutFrame(nullptr, nullptr, nullptr));
3042 for (auto i = nActions; 0 < i; --i)
3044 rUndoManager.Undo();
3046 for (SwNodeOffset i(0); i < pDoc->GetNodes().Count(); ++i)
3048 if (SwTextNode const* const pNode = pDoc->GetNodes()[i]->GetTextNode())
3050 CPPUNIT_ASSERT(pNode->getLayoutFrame(nullptr, nullptr, nullptr));
3055 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf139922)
3057 createSwDoc();
3059 SwXTextDocument* pTextDoc = getSwTextDoc();
3060 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RETURN);
3061 Scheduler::ProcessEventsToIdle();
3063 emulateTyping(u"this is a SEntence. this is a SEntence.");
3065 // Without the fix in place, this test would have failed with
3066 // - Expected: This is a Sentence. This is a Sentence.
3067 // - Actual : this is a Sentence. This is a Sentence.
3068 CPPUNIT_ASSERT_EQUAL(u"This is a Sentence. This is a Sentence."_ustr,
3069 getParagraph(2)->getString());
3072 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf143176)
3074 // Hungarian test document with right-to-left paragraph setting
3075 createSwDoc("tdf143176.fodt");
3077 // transliterate the document to Old Hungarian (note: it only works
3078 // with right-to-left text direction and Default Paragraph Style)
3079 dispatchCommand(mxComponent, u".uno:AutoFormatApply"_ustr, {});
3081 // This was the original "Lorem ipsum..."
3082 CPPUNIT_ASSERT_EQUAL(u"𐲖𐳛𐳢𐳉𐳘 𐳐𐳠𐳤𐳪𐳘 𐳇𐳛𐳖𐳛𐳢 "
3083 u"𐳤𐳐𐳦 𐳀𐳘𐳉𐳦⹁"_ustr,
3084 getParagraph(1)->getString());
3085 CPPUNIT_ASSERT_EQUAL(u"𐳄𐳛𐳙𐳤𐳉𐳄𐳦𐳉𐳦𐳪𐳢 "
3086 u"𐳀𐳇𐳐𐳠𐳐𐳤𐳄𐳐𐳙𐳍 𐳉𐳖𐳐𐳦."_ustr,
3087 getParagraph(2)->getString());
3090 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testInsertLongDateFormat)
3092 // only for Hungarian, yet
3093 createSwDoc("tdf133524.fodt");
3094 dispatchCommand(mxComponent, u".uno:InsertDateField"_ustr, {});
3095 // Make sure that the document starts with a field now, and its expanded string value contains space
3096 const uno::Reference<text::XTextRange> xField = getRun(getParagraph(1), 1);
3097 CPPUNIT_ASSERT_EQUAL(u"TextField"_ustr, getProperty<OUString>(xField, u"TextPortionType"_ustr));
3098 // the date format was "YYYY-MM-DD", but now "YYYY. MMM DD."
3099 CPPUNIT_ASSERT(xField->getString().indexOf(" ") > -1);
3102 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf129270)
3104 createSwDoc("tdf129270.odt");
3105 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
3106 CPPUNIT_ASSERT(pWrtShell);
3108 // Go to document end
3109 pWrtShell->SttEndDoc(/*bStt=*/false);
3111 // Press enter
3112 SwXTextDocument* pTextDoc = getSwTextDoc();
3113 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RETURN);
3114 Scheduler::ProcessEventsToIdle();
3116 // Numbering for previous outline should remain the same "2"
3117 CPPUNIT_ASSERT_EQUAL(u"2"_ustr,
3118 getProperty<OUString>(getParagraph(4), u"ListLabelString"_ustr));
3120 // Numbering for newly created outline should be "2.1"
3121 CPPUNIT_ASSERT_EQUAL(u"2.1"_ustr,
3122 getProperty<OUString>(getParagraph(5), u"ListLabelString"_ustr));
3125 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testInsertPdf)
3127 auto pPdfium = vcl::pdf::PDFiumLibrary::get();
3128 if (!pPdfium)
3130 return;
3133 createSwDoc();
3135 // insert the PDF into the document
3136 uno::Sequence<beans::PropertyValue> aArgs(comphelper::InitPropertySequence(
3137 { { "FileName", uno::Any(createFileURL(u"hello-world.pdf")) } }));
3138 dispatchCommand(mxComponent, u".uno:InsertGraphic"_ustr, aArgs);
3140 // Save and load cycle
3141 saveAndReload(u"writer8"_ustr);
3143 uno::Reference<drawing::XShape> xShape = getShape(1);
3144 // Assert that we have a replacement graphics
3145 auto xReplacementGraphic
3146 = getProperty<uno::Reference<graphic::XGraphic>>(xShape, u"ReplacementGraphic"_ustr);
3147 CPPUNIT_ASSERT(xReplacementGraphic.is());
3149 auto xGraphic = getProperty<uno::Reference<graphic::XGraphic>>(xShape, u"Graphic"_ustr);
3150 CPPUNIT_ASSERT(xGraphic.is());
3151 // Assert that the graphic is a PDF
3152 CPPUNIT_ASSERT_EQUAL(u"application/pdf"_ustr,
3153 getProperty<OUString>(xGraphic, u"MimeType"_ustr));
3156 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf143760WrapContourToOff)
3158 // Actually, this is an ooxmlexport test. It is here because here is a ready environment
3159 // to change a shape by dispatchCommand.
3160 createSwDoc("tdf143760_ContourToWrapOff.docx");
3161 SwDoc* pDoc = getSwDoc();
3162 CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(getShape(1), u"SurroundContour"_ustr));
3164 // Mark the object
3165 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
3166 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
3167 SdrObject* pObject = pPage->GetObj(0);
3168 CPPUNIT_ASSERT(pObject);
3169 SdrView* pView = pWrtShell->GetDrawView();
3170 pView->MarkObj(pObject, pView->GetSdrPageView());
3172 // Set "wrap off"
3173 dispatchCommand(mxComponent, u".uno:WrapOff"_ustr, {});
3174 CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(getShape(1), u"SurroundContour"_ustr));
3176 // Without fix this had failed, because the shape was written to file with contour.
3177 saveAndReload(u"Office Open XML Text"_ustr);
3178 CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(getShape(1), u"SurroundContour"_ustr));
3181 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testHatchFill)
3183 createSwDoc();
3185 // Add a rectangle shape to the document.
3186 uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
3187 uno::Reference<drawing::XShape> xShape(
3188 xFactory->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr), uno::UNO_QUERY);
3189 xShape->setSize(awt::Size(10000, 10000));
3190 xShape->setPosition(awt::Point(1000, 1000));
3191 uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY);
3192 xShapeProps->setPropertyValue(u"FillStyle"_ustr, uno::Any(drawing::FillStyle_HATCH));
3193 xShapeProps->setPropertyValue(u"FillHatchName"_ustr, uno::Any(u"Black 0 Degrees"_ustr));
3194 xShapeProps->setPropertyValue(u"FillBackground"_ustr, uno::Any(false));
3195 xShapeProps->setPropertyValue(u"FillTransparence"_ustr, uno::Any(sal_Int32(30)));
3196 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
3197 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
3198 xDrawPage->add(xShape);
3200 // Save it as DOCX and load it again.
3201 saveAndReload(u"Office Open XML Text"_ustr);
3202 CPPUNIT_ASSERT_EQUAL(1, getShapes());
3204 // tdf#127989 Without fix this had failed, because the background of the hatch was not set as 'no background'.
3205 CPPUNIT_ASSERT(!getProperty<bool>(getShape(1), u"FillBackground"_ustr));
3207 // tdf#146822 Without fix this had failed, because the transparency value of the hatch was not exported.
3208 CPPUNIT_ASSERT_EQUAL(sal_Int32(30),
3209 getProperty<sal_Int32>(getShape(1), u"FillTransparence"_ustr));
3212 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testNestedGroupTextBoxCopyCrash)
3214 createSwDoc("tdf149550.docx");
3216 CPPUNIT_ASSERT_EQUAL(1, getShapes());
3218 dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
3219 dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
3220 // This crashed here before the fix.
3221 SwXTextDocument* pTextDoc = getSwTextDoc();
3222 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_ESCAPE);
3223 Scheduler::ProcessEventsToIdle();
3224 dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
3226 CPPUNIT_ASSERT_EQUAL(2, getShapes());
3228 auto pLayout = parseLayoutDump();
3229 // There must be 2 textboxes!
3230 assertXPath(pLayout, "/root/page/body/txt/anchored/fly[2]");
3233 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testCrashOnExit)
3235 // Load the bugdoc with a table and a textbox shape inside.
3236 createSwDoc("tdf142715.odt");
3238 // Get the textbox selected
3239 CPPUNIT_ASSERT_EQUAL(1, getShapes());
3241 selectShape(1);
3242 auto xShape = getShape(1);
3243 uno::Reference<beans::XPropertySet> xProperties(xShape, uno::UNO_QUERY);
3245 // Check if the textbox is selected
3246 CPPUNIT_ASSERT_EQUAL(true, xProperties->getPropertyValue(u"TextBox"_ustr).get<bool>());
3248 // Remove the textbox
3249 dispatchCommand(mxComponent, u".uno:RemoveTextBox"_ustr, {});
3251 CPPUNIT_ASSERT_EQUAL(false, xProperties->getPropertyValue(u"TextBox"_ustr).get<bool>());
3253 // Readd the textbox (to run the textboxhelper::create() method)
3254 dispatchCommand(mxComponent, u".uno:AddTextBox"_ustr, {});
3256 CPPUNIT_ASSERT_EQUAL(true, xProperties->getPropertyValue(u"TextBox"_ustr).get<bool>());
3258 // save and reload
3259 // Before the fix this crashed here and could not reopen.
3260 saveAndReload(u"writer8"_ustr);
3263 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testCaptionShape)
3265 createSwDoc();
3267 // Add a caption shape to the document.
3268 uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
3269 uno::Reference<drawing::XShape> xShape(
3270 xFactory->createInstance(u"com.sun.star.drawing.CaptionShape"_ustr), uno::UNO_QUERY);
3271 xShape->setSize(awt::Size(10000, 10000));
3272 xShape->setPosition(awt::Point(1000, 1000));
3273 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
3274 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
3275 xDrawPage->add(xShape);
3277 // Save it as DOCX and load it again.
3278 saveAndReload(u"Office Open XML Text"_ustr);
3280 // Without fix in place, the shape was lost on export.
3281 CPPUNIT_ASSERT_EQUAL(1, getShapes());
3284 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf151828_Comment2)
3286 createSwDoc();
3288 // Add a basic shape to the document.
3289 uno::Sequence<beans::PropertyValue> aArgs(
3290 comphelper::InitPropertySequence({ { "KeyModifier", uno::Any(KEY_MOD1) } }));
3291 dispatchCommand(mxComponent, u".uno:BasicShapes"_ustr, aArgs);
3293 auto xBasicShape = getShape(1);
3294 auto pObject = SdrObject::getSdrObjectFromXShape(xBasicShape);
3296 CPPUNIT_ASSERT_EQUAL(1, getShapes());
3298 // rename the shape name
3299 pObject->SetName(u"Shape"_ustr);
3301 // cut and paste it
3302 dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});
3304 CPPUNIT_ASSERT_EQUAL(0, getShapes());
3306 dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
3308 CPPUNIT_ASSERT_EQUAL(1, getShapes());
3310 // it is required to get the shape object again after paste
3311 xBasicShape = getShape(1);
3312 pObject = SdrObject::getSdrObjectFromXShape(xBasicShape);
3314 // Without fix in place, the shape name was 'Shape 1' after paste.
3315 CPPUNIT_ASSERT_EQUAL(u"Shape"_ustr, pObject->GetName());
3318 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf151828)
3320 createSwDoc();
3321 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
3323 // insert a table
3324 SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
3325 pWrtShell->InsertTable(TableOpt, 1, 1);
3327 // move cursor into the table
3328 CPPUNIT_ASSERT(pWrtShell->MoveTable(GotoPrevTable, fnTableStart));
3330 SwFrameFormat* pFormat = pWrtShell->GetTableFormat();
3331 CPPUNIT_ASSERT(pFormat);
3333 // set name of table to 'MyTableName'
3334 pWrtShell->SetTableName(*pFormat, u"MyTableName"_ustr);
3336 // cut and paste the table
3337 dispatchCommand(mxComponent, u".uno:SelectTable"_ustr, {});
3338 dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});
3339 dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
3341 // move cursor into the pasted table
3342 CPPUNIT_ASSERT(pWrtShell->MoveTable(GotoPrevTable, fnTableStart));
3344 pFormat = pWrtShell->GetTableFormat();
3345 CPPUNIT_ASSERT(pFormat);
3347 // Before the fix the pasted table name was 'Table1'.
3348 CPPUNIT_ASSERT_EQUAL(u"MyTableName"_ustr, pFormat->GetName());
3351 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf146178)
3353 createSwDoc();
3355 SwDoc* pDoc = getSwDoc();
3356 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
3357 SwCursorShell* pShell(pDoc->GetEditShell());
3358 CPPUNIT_ASSERT(pShell);
3359 SwPaM* pCursor = pShell->GetCursor();
3361 // insert two fields
3362 dispatchCommand(mxComponent, u".uno:InsertTimeField"_ustr, {});
3363 dispatchCommand(mxComponent, u".uno:InsertDateField"_ustr, {});
3365 // navigate by field
3366 SwView::SetMoveType(NID_FIELD);
3368 // set cursor to the start of the document
3369 pWrtShell->SttEndDoc(false);
3370 // navigate to the previous field
3371 dispatchCommand(mxComponent, u".uno:ScrollToPrevious"_ustr, {});
3372 // Before the fix the position would be 0, navigation did not wrap to end of document
3373 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pCursor->GetPoint()->GetContentIndex());
3375 // set cursor to the end of the document
3376 pWrtShell->SttEndDoc(false);
3377 // navigate to the next field
3378 dispatchCommand(mxComponent, u".uno:ScrollToNext"_ustr, {});
3379 // Before the fix the position would be 1, navigation did not wrap to start of document
3380 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pCursor->GetPoint()->GetContentIndex());
3383 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf106663HeaderTextFrameGoToNextPlacemarker)
3385 createSwDoc("testTdf106663.odt");
3387 SwDoc* pDoc = getSwDoc();
3388 SwCursorShell* pShell(pDoc->GetEditShell());
3389 CPPUNIT_ASSERT(pShell);
3390 SwPaM* pCursor = pShell->GetCursor();
3391 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
3393 // Move the cursor into the fly frame of the document's header
3394 pWrtShell->GotoFly(u"FrameInHeader"_ustr, FLYCNTTYPE_FRM, false);
3396 // Check that GoToNextPlacemarker highlights the first field instead of the second one
3397 dispatchCommand(mxComponent, u".uno:GoToNextPlacemarker"_ustr, {});
3398 // Without the fix in place, this test would have failed with
3399 // - Expected: Heading
3400 // - Actual : Some other marker
3401 // i.e. the GoToNextPlacemarker command skipped the first field
3402 CPPUNIT_ASSERT(pCursor->GetPoint()->GetNode().GetTextNode()->GetText().startsWith("Heading"));
3405 CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf158454)
3407 createSwDoc("tdf158454.odt");
3408 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
3409 CPPUNIT_ASSERT(pWrtShell);
3411 // * without change tracking
3412 CPPUNIT_ASSERT(!(pWrtShell->GetRedlineFlags() & RedlineFlags::On));
3414 // Thai single autocorrect (อนุญาติ -> อนุญาต)
3415 emulateTyping(u"อนุญาติ ");
3416 OUString sReplaced = u"อนุญาต (จบ)"_ustr;
3417 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
3419 // Thai multiple autocorrects (กงศุลสังเกตุกระทันหัน -> กงสุลสังเกตกะทันหัน)
3420 emulateTyping(u"กงศุลสังเกตุกระทันหัน ");
3421 sReplaced = u"อนุญาต กงสุลสังเกตกะทันหัน (จบ)"_ustr;
3422 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
3424 // * with change tracking (showing redlines)
3425 RedlineFlags const nMode(pWrtShell->GetRedlineFlags() | RedlineFlags::On);
3426 CPPUNIT_ASSERT(nMode & (RedlineFlags::ShowDelete | RedlineFlags::ShowInsert));
3427 pWrtShell->SetRedlineFlags(nMode);
3428 CPPUNIT_ASSERT(nMode & RedlineFlags::On);
3429 CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);
3431 // Thai single autocorrect (อนุญาติ -> อนุญาต)
3432 emulateTyping(u"อนุญาติ ");
3433 sReplaced = u"อนุญาต กงสุลสังเกตกะทันหัน อนุญาต (จบ)"_ustr;
3434 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
3436 // Thai multiple autocorrects (กงศุลสังเกตุกระทันหัน -> กงสุลสังเกตกะทันหัน)
3437 emulateTyping(u"กงศุลสังเกตุกระทันหัน ");
3438 sReplaced = u"อนุญาต กงสุลสังเกตกะทันหัน อนุญาต กงสุลสังเกตกะทันหัน (จบ)"_ustr;
3439 CPPUNIT_ASSERT_EQUAL(sReplaced, getParagraph(1)->getString());
3442 CPPUNIT_PLUGIN_IMPLEMENT();
3444 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */