remove assert looking for new compatibilityMode DOCX
[LibreOffice.git] / sw / qa / extras / uiwriter / uiwriter4.cxx
blobaeb226ec595f1453bca4a2f5a4d5ee19dd4793b1
2 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 /*
4 * This file is part of the LibreOffice project.
6 * This Source Code Form is subject to the terms of the Mozilla Public
7 * License, v. 2.0. If a copy of the MPL was not distributed with this
8 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 */
11 #include <com/sun/star/drawing/FillStyle.hpp>
12 #include <com/sun/star/style/CaseMap.hpp>
13 #include <swmodeltestbase.hxx>
14 #include <ndtxt.hxx>
15 #include <wrtsh.hxx>
16 #include <drawdoc.hxx>
17 #include <redline.hxx>
18 #include <dcontact.hxx>
19 #include <view.hxx>
20 #include <IDocumentSettingAccess.hxx>
22 #include <editeng/brushitem.hxx>
23 #include <svx/svdpage.hxx>
24 #include <svx/svdview.hxx>
26 #include <i18nutil/transliteration.hxx>
27 #include <IDocumentDrawModelAccess.hxx>
28 #include <IDocumentRedlineAccess.hxx>
29 #include <UndoManager.hxx>
30 #include <tblafmt.hxx>
32 #include <com/sun/star/text/XTextField.hpp>
33 #include <com/sun/star/linguistic2/XLinguProperties.hpp>
34 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
35 #include <com/sun/star/text/XPageCursor.hpp>
36 #include <com/sun/star/text/XParagraphAppend.hpp>
37 #include <o3tl/cppunittraitshelper.hxx>
38 #include <osl/thread.hxx>
39 #include <hyp.hxx>
40 #include <swdtflvr.hxx>
41 #include <comphelper/propertysequence.hxx>
42 #include <sfx2/classificationhelper.hxx>
43 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
44 #include <sfx2/viewfrm.hxx>
45 #include <sfx2/dispatch.hxx>
46 #include <editeng/unolingu.hxx>
47 #include <vcl/scheduler.hxx>
48 #include <config_fonts.h>
49 #include <unotxdoc.hxx>
50 #include <unotools/transliterationwrapper.hxx>
51 #include <officecfg/Office/Writer.hxx>
53 namespace
55 void lcl_selectCharacters(SwPaM& rPaM, sal_Int32 first, sal_Int32 end)
57 rPaM.GetPoint()->nContent.Assign(rPaM.GetPointContentNode(), first);
58 rPaM.SetMark();
59 rPaM.GetPoint()->nContent.Assign(rPaM.GetPointContentNode(), end);
61 } //namespace
63 class SwUiWriterTest4 : public SwModelTestBase
65 public:
66 SwUiWriterTest4()
67 : SwModelTestBase(u"/sw/qa/extras/uiwriter/data/"_ustr)
71 void mergeDocs(const char* aDestDoc, const char* aInsertDoc);
74 void SwUiWriterTest4::mergeDocs(const char* aDestDoc, const char* aInsertDoc)
76 createSwDoc(aDestDoc);
78 // set a page cursor into the end of the document
79 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
80 uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
81 xModel->getCurrentController(), uno::UNO_QUERY);
82 uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(),
83 uno::UNO_QUERY);
84 xCursor->jumpToEndOfPage();
86 // insert the same document at current cursor position
88 const OUString insertFileid = createFileURL(OUString::createFromAscii(aInsertDoc));
89 uno::Sequence<beans::PropertyValue> aPropertyValues(
90 comphelper::InitPropertySequence({ { "Name", uno::Any(insertFileid) } }));
91 dispatchCommand(mxComponent, u".uno:InsertDoc"_ustr, aPropertyValues);
95 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf96515)
97 // Enable hide whitespace mode.
98 createSwDoc();
99 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
100 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
101 aViewOptions.SetHideWhitespaceMode(true);
102 pWrtShell->ApplyViewOptions(aViewOptions);
103 CPPUNIT_ASSERT(pWrtShell->GetViewOptions()->IsWhitespaceHidden());
105 // Insert a new paragraph at the end of the document.
106 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
107 uno::Reference<text::XParagraphAppend> xParagraphAppend(xTextDocument->getText(),
108 uno::UNO_QUERY);
109 xParagraphAppend->finishParagraph(uno::Sequence<beans::PropertyValue>());
110 calcLayout();
112 // This was 2, a new page was created for the new paragraph.
113 CPPUNIT_ASSERT_EQUAL(1, getPages());
116 static OUString lcl_translitTest(SwDoc& rDoc, const SwPaM& rPaM, TransliterationFlags const nType)
118 utl::TransliterationWrapper aTrans(::comphelper::getProcessComponentContext(), nType);
119 rDoc.getIDocumentContentOperations().TransliterateText(rPaM, aTrans);
120 //SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
121 return rPaM.GetMarkNode().GetTextNode()->GetText();
124 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf146449)
126 createSwDoc("tdf146449.odt");
128 auto pShell = getSwDocShell()->GetFEShell();
129 CPPUNIT_ASSERT(pShell);
131 auto xTextBox = getShapeByName(u"Frame1");
132 auto pObject = SdrObject::getSdrObjectFromXShape(xTextBox);
134 CPPUNIT_ASSERT(pShell->SelectObj(Point(), 0, pObject));
136 dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});
138 dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
140 uno::Reference<beans::XPropertySet> xShapeProps(xTextBox, uno::UNO_QUERY);
141 uno::Reference<beans::XPropertySet> xFrameProps(
142 xShapeProps->getPropertyValue(u"TextBoxContent"_ustr), uno::UNO_QUERY);
144 const auto nShapeZOrder = pObject->GetOrdNum();
145 const auto nFrameZOrder = xFrameProps->getPropertyValue(u"ZOrder"_ustr);
147 CPPUNIT_ASSERT_MESSAGE("Wrong Zorder!", nShapeZOrder < nFrameZOrder.get<sal_uInt32>());
150 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf49033)
152 createSwDoc();
153 SwDoc* pDoc = getSwDoc();
154 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
156 // Insert the test text at the end of the document.
157 pWrtShell->SttEndDoc(/*bStt=*/false);
158 pWrtShell->Insert(u"Mary Jones met joe Smith. Time Passed."_ustr);
159 pWrtShell->StartOfSection();
160 SwShellCursor* pCursor = pWrtShell->getShellCursor(false);
162 using TF = TransliterationFlags;
164 /* -- Test behavior when there is no selection -- */
166 /* Move cursor between the 't' and the ' ' after 'met', nothing should change */
167 for (int i = 0; i < 14; i++)
168 pCursor->Move(fnMoveForward);
170 CPPUNIT_ASSERT_EQUAL(false, pCursor->HasMark());
171 CPPUNIT_ASSERT_EQUAL(false, pWrtShell->IsSelection());
172 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
173 lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
174 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
175 lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
176 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
177 lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
178 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
179 lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
181 /* Move cursor between the 'h' and the '.' after 'Smith', nothing should change */
182 for (int i = 0; i < 10; i++)
183 pCursor->Move(fnMoveForward);
185 CPPUNIT_ASSERT_EQUAL(false, pCursor->HasMark());
186 CPPUNIT_ASSERT_EQUAL(false, pWrtShell->IsSelection());
187 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
188 lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
189 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
190 lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
191 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
192 lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
193 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
194 lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
196 /* Move cursor between the 'm' and the 'e' in 'met' */
197 for (int i = 0; i < 12; i++)
198 pCursor->Move(fnMoveBackward);
200 CPPUNIT_ASSERT_EQUAL(false, pCursor->HasMark());
201 CPPUNIT_ASSERT_EQUAL(false, pWrtShell->IsSelection());
202 CPPUNIT_ASSERT_EQUAL(u"Mary jones met joe smith. Time Passed."_ustr,
203 lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
205 /* Undo the sentence case change to reset for the following tests */
206 pDoc->GetIDocumentUndoRedo().Undo();
208 CPPUNIT_ASSERT_EQUAL(u"Mary Jones Met joe Smith. Time Passed."_ustr,
209 lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
210 CPPUNIT_ASSERT_EQUAL(u"Mary Jones MET joe Smith. Time Passed."_ustr,
211 lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
212 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
213 lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
215 /* -- Test behavior when there is a selection that does not cross a word boundary -- */
216 pCursor->Move(fnMoveBackward);
217 pWrtShell->SelWrd();
218 CPPUNIT_ASSERT_EQUAL(true, pCursor->HasMark());
219 CPPUNIT_ASSERT_EQUAL(true, pWrtShell->IsSelection());
221 OUString currentSelectedText;
222 pWrtShell->GetSelectedText(currentSelectedText);
223 CPPUNIT_ASSERT_EQUAL(u"met"_ustr, currentSelectedText);
224 CPPUNIT_ASSERT_EQUAL(u"Mary Jones Met joe Smith. Time Passed."_ustr,
225 lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
226 CPPUNIT_ASSERT_EQUAL(u"Mary Jones Met joe Smith. Time Passed."_ustr,
227 lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
228 CPPUNIT_ASSERT_EQUAL(u"Mary Jones MET joe Smith. Time Passed."_ustr,
229 lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
230 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
231 lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
233 /* -- Test behavior when there is a selection that does not begin at a word boundary: "et" -- */
234 for (int i = 0; i < 2; i++)
235 pCursor->Move(fnMoveBackward);
236 pCursor->SetMark();
237 for (int i = 0; i < 2; i++)
238 pCursor->Move(fnMoveForward);
239 pWrtShell->GetSelectedText(currentSelectedText);
240 CPPUNIT_ASSERT_EQUAL(u"et"_ustr, currentSelectedText);
241 CPPUNIT_ASSERT_EQUAL(u"Mary Jones mEt joe Smith. Time Passed."_ustr,
242 lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
243 pDoc->GetIDocumentUndoRedo().Undo();
244 CPPUNIT_ASSERT_EQUAL(u"et"_ustr, currentSelectedText);
245 CPPUNIT_ASSERT_EQUAL(u"Mary Jones mEt joe Smith. Time Passed."_ustr,
246 lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
247 pDoc->GetIDocumentUndoRedo().Undo();
248 CPPUNIT_ASSERT_EQUAL(u"et"_ustr, currentSelectedText);
249 CPPUNIT_ASSERT_EQUAL(u"Mary Jones mET joe Smith. Time Passed."_ustr,
250 lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
251 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
252 lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
254 /* -- Test behavior when there is a selection that crosses a word boundary -- */
255 for (int i = 0; i < 7; i++)
256 pCursor->Move(fnMoveBackward);
257 pCursor->SetMark();
258 for (int i = 0; i < 14; i++)
259 pCursor->Move(fnMoveForward);
261 pWrtShell->GetSelectedText(currentSelectedText);
262 CPPUNIT_ASSERT_EQUAL(u"nes met joe Sm"_ustr, currentSelectedText);
263 CPPUNIT_ASSERT_EQUAL(u"Mary JoNes met joe smith. Time Passed."_ustr,
264 lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
265 CPPUNIT_ASSERT_EQUAL(u"Mary JoNes Met Joe Smith. Time Passed."_ustr,
266 lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
267 CPPUNIT_ASSERT_EQUAL(u"Mary JoNES MET JOE SMith. Time Passed."_ustr,
268 lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
269 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe smith. Time Passed."_ustr,
270 lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
272 /* Reset the 's' to upper-case for the next test */
273 for (int i = 0; i < 2; i++)
274 pCursor->Move(fnMoveBackward);
275 pCursor->SetMark();
276 pCursor->Move(fnMoveForward);
277 pDoc->getIDocumentContentOperations().ReplaceRange(*pCursor, OUString('S'), false);
279 /* -- Test behavior when there is a selection that crosses a sentence boundary -- */
280 for (int i = 0; i < 4; i++)
281 pCursor->Move(fnMoveBackward);
282 pCursor->SetMark();
283 for (int i = 0; i < 22; i++)
284 pCursor->Move(fnMoveForward);
285 pWrtShell->GetSelectedText(currentSelectedText);
286 CPPUNIT_ASSERT_EQUAL(u"joe Smith. Time Passed"_ustr, currentSelectedText);
288 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met Joe smith. Time passed."_ustr,
289 lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
291 /* Undo the sentence case change to reset for the following tests */
292 pDoc->GetIDocumentUndoRedo().Undo();
294 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met Joe Smith. Time Passed."_ustr,
295 lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
296 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met JOE SMITH. TIME PASSED."_ustr,
297 lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
298 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe smith. time passed."_ustr,
299 lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
301 /* Undo the previous changes to reset for the following tests */
302 pDoc->GetIDocumentUndoRedo().Undo();
303 pDoc->GetIDocumentUndoRedo().Undo();
304 pDoc->GetIDocumentUndoRedo().Undo();
306 /* -- Test behavior when there is a selection that does not reach end of sentence -- */
307 for (int i = 0; i < 37; i++)
308 pCursor->Move(fnMoveBackward);
309 pCursor->SetMark();
310 for (int i = 0; i < 10; i++)
311 pCursor->Move(fnMoveForward);
312 pWrtShell->GetSelectedText(currentSelectedText);
313 CPPUNIT_ASSERT_EQUAL(u"Mary Jones"_ustr, currentSelectedText);
314 CPPUNIT_ASSERT_EQUAL(u"Mary jones met joe Smith. Time Passed."_ustr,
315 lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
316 CPPUNIT_ASSERT_EQUAL(u"Mary Jones met joe Smith. Time Passed."_ustr,
317 lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
318 CPPUNIT_ASSERT_EQUAL(u"MARY JONES met joe Smith. Time Passed."_ustr,
319 lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
320 CPPUNIT_ASSERT_EQUAL(u"mary jones met joe Smith. Time Passed."_ustr,
321 lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
324 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf147196)
326 using TF = TransliterationFlags;
327 createSwDoc();
328 SwDoc* pDoc = getSwDoc();
329 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
331 // Insert the test text at the end of the document.
332 pWrtShell->SttEndDoc(/*bStt=*/false);
333 pWrtShell->Insert(
334 u"2.2 Publication of information - CAA\nSection 4.2 of a CA\'s Certificate Policy and/or "
335 "Certification Practice Statement SHALL state the CA\'s policy or practice on processing "
336 "CAA Records for Fully Qualified Domain Names; that policy shall be consistent with these "
337 "Requirements. \n\nIt shall clearly specify the set of Issuer Domain Names that the CA "
338 "recognises in CAA \"issue\" or \"issuewild\" records as permitting it to issue. The CA "
339 "SHALL log all actions taken, if any, consistent with its processing practice."_ustr);
341 pWrtShell->StartOfSection();
342 SwShellCursor* pCursor = pWrtShell->getShellCursor(false);
343 pCursor->SetMark();
344 for (int i = 0; i < 510; i++)
346 pCursor->Move(fnMoveForward);
348 CPPUNIT_ASSERT_EQUAL(
349 u"2.2 Publication Of Information - Caa\nSection 4.2 Of A Ca\'s Certificate Policy "
350 "And/Or Certification Practice Statement Shall State The Ca\'s Policy Or Practice "
351 "On Processing Caa Records For Fully Qualified Domain Names; That Policy Shall Be "
352 "Consistent With These Requirements. \n\nIt Shall Clearly Specify The Set Of "
353 "Issuer Domain Names That The Ca Recognises In Caa \"Issue\" Or \"Issuewild\" "
354 "Records As Permitting It To Issue. The Ca Shall Log All Actions Taken, If Any, "
355 "Consistent With Its Processing Practice."_ustr,
356 lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
359 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf148148)
361 using TF = TransliterationFlags;
362 createSwDoc();
363 SwDoc* pDoc = getSwDoc();
364 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
366 pWrtShell->SttEndDoc(/*bStt=*/false);
367 pWrtShell->Insert(u" text"_ustr);
369 /* Test what happens when node contains text but selection does not contain any text */
370 pWrtShell->StartOfSection();
371 SwShellCursor* pCursor = pWrtShell->getShellCursor(false);
372 pCursor->SetMark();
373 for (int i = 0; i < 3; i++)
375 pCursor->Move(fnMoveForward);
377 CPPUNIT_ASSERT_EQUAL(u" text"_ustr, lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
378 CPPUNIT_ASSERT_EQUAL(u" text"_ustr, lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
379 CPPUNIT_ASSERT_EQUAL(u" text"_ustr,
380 lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
381 CPPUNIT_ASSERT_EQUAL(u" text"_ustr,
382 lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
384 /* Test what happens when node contains text but selection does not contain any text */
385 createSwDoc();
386 pDoc = getSwDoc();
387 pWrtShell = getSwDocShell()->GetWrtShell();
388 pWrtShell->SttEndDoc(/*bStt=*/false);
389 pWrtShell->Insert(u"text "_ustr);
391 pWrtShell->StartOfSection();
392 pCursor = pWrtShell->getShellCursor(false);
393 for (int i = 0; i < 4; i++)
395 pCursor->Move(fnMoveForward);
397 pCursor->SetMark();
398 for (int i = 0; i < 2; i++)
400 pCursor->Move(fnMoveForward);
403 CPPUNIT_ASSERT_EQUAL(u"text "_ustr, lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
404 CPPUNIT_ASSERT_EQUAL(u"text "_ustr, lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
405 CPPUNIT_ASSERT_EQUAL(u"text "_ustr,
406 lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
407 CPPUNIT_ASSERT_EQUAL(u"text "_ustr,
408 lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
410 /* Test what happens when node contains only non-word text but selection does not contain any text */
411 createSwDoc();
412 pDoc = getSwDoc();
413 pWrtShell = getSwDocShell()->GetWrtShell();
414 pWrtShell->SttEndDoc(/*bStt=*/false);
415 pWrtShell->Insert(u"-1 "_ustr);
417 pWrtShell->StartOfSection();
418 pCursor = pWrtShell->getShellCursor(false);
419 for (int i = 0; i < 2; i++)
421 pCursor->Move(fnMoveForward);
423 pCursor->SetMark();
424 for (int i = 0; i < 2; i++)
426 pCursor->Move(fnMoveForward);
429 CPPUNIT_ASSERT_EQUAL(u"-1 "_ustr, lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
430 CPPUNIT_ASSERT_EQUAL(u"-1 "_ustr, lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
431 CPPUNIT_ASSERT_EQUAL(u"-1 "_ustr, lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
432 CPPUNIT_ASSERT_EQUAL(u"-1 "_ustr, lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
434 createSwDoc();
435 pDoc = getSwDoc();
436 pWrtShell = getSwDocShell()->GetWrtShell();
437 pWrtShell->SttEndDoc(/*bStt=*/false);
438 pWrtShell->Insert(u" -1"_ustr);
440 pWrtShell->StartOfSection();
441 pCursor = pWrtShell->getShellCursor(false);
442 pCursor->SetMark();
443 for (int i = 0; i < 2; i++)
445 pCursor->Move(fnMoveForward);
448 CPPUNIT_ASSERT_EQUAL(u" -1"_ustr, lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
449 CPPUNIT_ASSERT_EQUAL(u" -1"_ustr, lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
450 CPPUNIT_ASSERT_EQUAL(u" -1"_ustr, lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
451 CPPUNIT_ASSERT_EQUAL(u" -1"_ustr, lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
453 /* Test what happens when node and selection contains only non-word text */
454 createSwDoc();
455 pDoc = getSwDoc();
456 pWrtShell = getSwDocShell()->GetWrtShell();
457 pWrtShell->SttEndDoc(/*bStt=*/false);
458 pWrtShell->Insert(u" -1"_ustr);
460 pWrtShell->StartOfSection();
461 pCursor = pWrtShell->getShellCursor(false);
462 pCursor->SetMark();
463 for (int i = 0; i < 5; i++)
465 pCursor->Move(fnMoveForward);
468 CPPUNIT_ASSERT_EQUAL(u" -1"_ustr, lcl_translitTest(*pDoc, *pCursor, TF::SENTENCE_CASE));
469 CPPUNIT_ASSERT_EQUAL(u" -1"_ustr, lcl_translitTest(*pDoc, *pCursor, TF::TITLE_CASE));
470 CPPUNIT_ASSERT_EQUAL(u" -1"_ustr, lcl_translitTest(*pDoc, *pCursor, TF::LOWERCASE_UPPERCASE));
471 CPPUNIT_ASSERT_EQUAL(u" -1"_ustr, lcl_translitTest(*pDoc, *pCursor, TF::UPPERCASE_LOWERCASE));
474 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf96943)
476 // Enable hide whitespace mode.
477 createSwDoc("tdf96943.odt");
478 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
479 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
480 aViewOptions.SetHideWhitespaceMode(true);
481 pWrtShell->ApplyViewOptions(aViewOptions);
483 // Insert a new character at the end of the document.
484 pWrtShell->SttEndDoc(/*bStt=*/false);
485 pWrtShell->Insert(u"d"_ustr);
487 // This was 2, a new page was created for the new layout line.
488 CPPUNIT_ASSERT_EQUAL(1, getPages());
491 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf96536)
493 // Enable hide whitespace mode.
494 createSwDoc();
495 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
496 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
497 aViewOptions.SetHideWhitespaceMode(true);
498 pWrtShell->ApplyViewOptions(aViewOptions);
499 CPPUNIT_ASSERT(pWrtShell->GetViewOptions()->IsWhitespaceHidden());
501 // Insert a page break and go back to the first page.
502 pWrtShell->InsertPageBreak();
503 pWrtShell->SttEndDoc(/*bStt=*/true);
504 calcLayout();
505 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
506 sal_Int32 nSingleParaPageHeight
507 = getXPath(pXmlDoc, "/root/page[1]/infos/bounds", "height").toInt32();
509 // Insert a 2nd paragraph at the end of the first page, so the page height grows at least twice...
510 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
511 uno::Reference<text::XParagraphAppend> xParagraphAppend(xTextDocument->getText(),
512 uno::UNO_QUERY);
513 const uno::Reference<text::XTextRange> xInsertPos = getRun(getParagraph(1), 1);
514 xParagraphAppend->finishParagraphInsert(uno::Sequence<beans::PropertyValue>(), xInsertPos);
515 calcLayout();
516 pXmlDoc = parseLayoutDump();
517 CPPUNIT_ASSERT(getXPath(pXmlDoc, "/root/page[1]/infos/bounds", "height").toInt32()
518 >= 2 * nSingleParaPageHeight);
520 // ... and then delete the 2nd paragraph, which shrinks the page to the previous size.
521 uno::Reference<lang::XComponent> xParagraph(getParagraph(2), uno::UNO_QUERY);
522 xParagraph->dispose();
523 calcLayout();
524 pXmlDoc = parseLayoutDump();
525 CPPUNIT_ASSERT_EQUAL(nSingleParaPageHeight,
526 getXPath(pXmlDoc, "/root/page[1]/infos/bounds", "height").toInt32());
529 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf96479)
531 // We want to verify the empty input text field in the bookmark
532 static const OUString emptyInputTextField
533 = OUStringChar(CH_TXT_ATR_INPUTFIELDSTART) + OUStringChar(CH_TXT_ATR_INPUTFIELDEND);
535 createSwDoc();
536 SwDoc* pDoc = getSwDoc();
538 // So we can clean up all references for reload
540 // Append bookmark
541 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
542 SwPaM aPaM(aIdx);
543 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
544 sw::mark::MarkBase* pMark
545 = rIDMA.makeMark(aPaM, u"original"_ustr, IDocumentMarkAccess::MarkType::BOOKMARK,
546 ::sw::mark::InsertMode::New);
547 CPPUNIT_ASSERT(!pMark->IsExpanded());
548 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
550 // Get helper objects
551 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
552 uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
554 // Create cursor from bookmark
555 uno::Reference<text::XTextContent> xTextContent(
556 xBookmarksSupplier->getBookmarks()->getByName(u"original"_ustr), uno::UNO_QUERY);
557 uno::Reference<text::XTextRange> xRange = xTextContent->getAnchor();
558 uno::Reference<text::XTextCursor> xCursor
559 = xRange->getText()->createTextCursorByRange(xRange);
560 CPPUNIT_ASSERT(xCursor->isCollapsed());
562 // Remove bookmark
563 xRange->getText()->removeTextContent(xTextContent);
564 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), rIDMA.getBookmarksCount());
566 // Insert replacement bookmark
567 uno::Reference<text::XTextContent> xBookmarkNew(
568 xFactory->createInstance(u"com.sun.star.text.Bookmark"_ustr), uno::UNO_QUERY);
569 uno::Reference<container::XNamed> xBookmarkName(xBookmarkNew, uno::UNO_QUERY);
570 xBookmarkName->setName(u"replacement"_ustr);
571 CPPUNIT_ASSERT(xCursor->isCollapsed());
572 // Force bookmark expansion
573 xCursor->getText()->insertString(xCursor, u"."_ustr, true);
574 xCursor->getText()->insertTextContent(xCursor, xBookmarkNew, true);
575 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
576 auto mark = *(rIDMA.getBookmarksBegin());
577 CPPUNIT_ASSERT(mark->IsExpanded());
579 // Create and insert input textfield with some content
580 uno::Reference<text::XTextField> xTextField(
581 xFactory->createInstance(u"com.sun.star.text.TextField.Input"_ustr), uno::UNO_QUERY);
582 uno::Reference<text::XTextCursor> xCursorNew(
583 xBookmarkNew->getAnchor()->getText()->createTextCursorByRange(
584 xBookmarkNew->getAnchor()));
585 CPPUNIT_ASSERT(!xCursorNew->isCollapsed());
586 xCursorNew->getText()->insertTextContent(xCursorNew, xTextField, true);
587 xBookmarkNew = uno::Reference<text::XTextContent>(
588 xBookmarksSupplier->getBookmarks()->getByName(u"replacement"_ustr), uno::UNO_QUERY);
589 xCursorNew = xBookmarkNew->getAnchor()->getText()->createTextCursorByRange(
590 xBookmarkNew->getAnchor());
591 CPPUNIT_ASSERT(!xCursorNew->isCollapsed());
593 // Can't check the actual content of the text node via UNO
594 mark = *(rIDMA.getBookmarksBegin());
595 CPPUNIT_ASSERT(mark->IsExpanded());
596 SwPaM pam(mark->GetMarkStart(), mark->GetMarkEnd());
597 // Check for the actual bug, which didn't include CH_TXT_ATR_INPUTFIELDEND in the bookmark
598 CPPUNIT_ASSERT_EQUAL(emptyInputTextField, pam.GetText());
602 // Save and load cycle
603 // Actually not needed, but the bug symptom of a missing bookmark
604 // occurred because a broken bookmark was saved and loading silently
605 // dropped the broken bookmark!
606 saveAndReload(u"writer8"_ustr);
607 pDoc = getSwDoc();
609 // Lookup "replacement" bookmark
610 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
611 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
612 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
613 CPPUNIT_ASSERT(xBookmarksSupplier->getBookmarks()->hasByName(u"replacement"_ustr));
615 uno::Reference<text::XTextContent> xTextContent(
616 xBookmarksSupplier->getBookmarks()->getByName(u"replacement"_ustr), uno::UNO_QUERY);
617 uno::Reference<text::XTextRange> xRange = xTextContent->getAnchor();
618 uno::Reference<text::XTextCursor> xCursor
619 = xRange->getText()->createTextCursorByRange(xRange);
620 CPPUNIT_ASSERT(!xCursor->isCollapsed());
622 // Verify bookmark content via text node / PaM
623 auto mark = *(rIDMA.getBookmarksBegin());
624 CPPUNIT_ASSERT(mark->IsExpanded());
625 SwPaM pam(mark->GetMarkStart(), mark->GetMarkEnd());
626 CPPUNIT_ASSERT_EQUAL(emptyInputTextField, pam.GetText());
630 // If you resave original document the bookmark will be changed from
632 // <text:p text:style-name="Standard">
633 // <text:bookmark-start text:name="test"/>
634 // <text:bookmark-end text:name="test"/>
635 // def
636 // </text:p>
638 // to
640 // <text:p text:style-name="Standard">
641 // <text:bookmark text:name="test"/>
642 // def
643 // </text:p>
645 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testBookmarkCollapsed)
647 // load document
648 createSwDoc("collapsed_bookmark.odt");
650 // save original document
651 save(u"writer8"_ustr);
653 // load only content.xml from the resaved document
654 xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
656 const char* const aPath("/office:document-content/office:body/office:text/text:p");
658 const int pos1 = getXPathPosition(pXmlDoc, aPath, "bookmark");
659 CPPUNIT_ASSERT_EQUAL(0, pos1); // found, and it is first
661 CPPUNIT_ASSERT_ASSERTION_FAIL(getXPathPosition(pXmlDoc, aPath, "bookmark-start")); // not found
662 CPPUNIT_ASSERT_ASSERTION_FAIL(getXPathPosition(pXmlDoc, aPath, "bookmark-end")); // not found
665 // 1. Open a new writer document
666 // 2. Enter the text "abcdef"
667 // 3. Select "abc"
668 // 4. Insert a bookmark on "abc" using Insert->Bookmark. Name the bookmark "test".
669 // 5. Open the navigator (F5)
670 // Select the bookmark "test" using the navigator.
671 // 6. Hit Del, thus deleting "abc" (The bookmark "test" is still there).
672 // 7. Save the document:
673 // <text:p text:style-name="Standard">
674 // <text:bookmark text:name="test"/>
675 // def
676 // </text:p>
678 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testRemoveBookmarkText)
680 // create document
682 // create a text document with "abcdef"
683 createSwDoc();
684 SwDoc* pDoc = getSwDoc();
687 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
688 SwPaM aPaM(aIdx);
689 pDoc->getIDocumentContentOperations().InsertString(aPaM, u"abcdef"_ustr);
692 // mark "abc" with "testBookmark" bookmark
694 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
695 SwPaM aPaM(aIdx);
697 lcl_selectCharacters(aPaM, 0, 3);
698 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
699 sw::mark::MarkBase* pMark = rIDMA.makeMark(aPaM, u"testBookmark"_ustr,
700 IDocumentMarkAccess::MarkType::BOOKMARK,
701 ::sw::mark::InsertMode::New);
703 // verify
704 CPPUNIT_ASSERT(pMark->IsExpanded());
705 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
708 // remove text marked with bookmark
710 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
711 SwPaM aPaM(aIdx);
713 lcl_selectCharacters(aPaM, 0, 3);
714 pDoc->getIDocumentContentOperations().DeleteRange(aPaM);
716 // verify: bookmark is still exist
717 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
718 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
722 // save document
723 save(u"writer8"_ustr);
725 // load only content.xml from the resaved document
726 xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
728 // Bookmark without text becomes collapsed
729 assertXPath(pXmlDoc, "//office:body/office:text/text:p/text:bookmark", 1);
730 assertXPath(pXmlDoc, "//office:body/office:text/text:p/text:bookmark-start", 0);
731 assertXPath(pXmlDoc, "//office:body/office:text/text:p/text:bookmark-end", 0);
734 // 1. Open a new writer document
735 // 2. Enter the text "abcdef"
736 // 3. Select "abc"
737 // 4. Insert a bookmark on "abc" using Insert->Bookmark. Name the bookmark "test".
738 // 5. Open the navigator (F5)
739 // Select the bookmark "test" using the navigator.
740 // 6. Hit Del, thus deleting "abc" (The bookmark "test" is still there).
741 // 7. Call our macro
743 // Sub Main
744 // bookmark = ThisComponent.getBookmarks().getByName("test")
745 // bookmark.getAnchor().setString("abc")
746 // End Sub
748 // The text "abc" gets inserted inside the bookmark "test", and the document now contains the string "abcdef".
749 // 7. Save the document:
750 // <text:p text:style-name="Standard">
751 // <text:bookmark-start text:name="test"/>
752 // abc
753 // <text:bookmark-end text:name="test"/>
754 // def
755 // </text:p>
757 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testRemoveBookmarkTextAndAddNew)
759 // create document
761 // create a text document with "abcdef"
762 createSwDoc();
763 SwDoc* pDoc = getSwDoc();
765 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
766 SwPaM aPaM(aIdx);
767 pDoc->getIDocumentContentOperations().InsertString(aPaM, u"abcdef"_ustr);
770 // mark "abc" with "testBookmark" bookmark
772 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
773 SwPaM aPaM(aIdx);
775 lcl_selectCharacters(aPaM, 0, 3);
776 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
777 sw::mark::MarkBase* pMark = rIDMA.makeMark(aPaM, u"testBookmark"_ustr,
778 IDocumentMarkAccess::MarkType::BOOKMARK,
779 ::sw::mark::InsertMode::New);
781 // verify
782 CPPUNIT_ASSERT(pMark->IsExpanded());
783 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
786 // remove text marked with bookmark
788 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
789 SwPaM aPaM(aIdx);
791 lcl_selectCharacters(aPaM, 0, 3);
792 pDoc->getIDocumentContentOperations().DeleteRange(aPaM);
794 // verify: bookmark is still exist
795 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
796 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
799 // write "abc" to area marked with "testBookmark" bookmark
801 // Get helper objects
802 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent,
803 uno::UNO_QUERY);
805 // Create cursor from bookmark
806 uno::Reference<text::XTextContent> xTextContent(
807 xBookmarksSupplier->getBookmarks()->getByName(u"testBookmark"_ustr),
808 uno::UNO_QUERY);
809 uno::Reference<text::XTextRange> xRange = xTextContent->getAnchor();
810 CPPUNIT_ASSERT_EQUAL(u""_ustr, xRange->getString());
812 // write "abc"
813 xRange->setString(u"abc"_ustr);
815 // verify: bookmark is still exist
816 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
817 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
821 // save document
822 save(u"writer8"_ustr);
824 // load only content.xml from the resaved document
825 xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
827 const char* const aPath("/office:document-content/office:body/office:text/text:p");
829 CPPUNIT_ASSERT_ASSERTION_FAIL(getXPathPosition(pXmlDoc, aPath, "bookmark")); // not found
830 const int pos2 = getXPathPosition(pXmlDoc, aPath, "bookmark-start");
831 const int pos3 = getXPathPosition(pXmlDoc, aPath, "text");
832 const int pos4 = getXPathPosition(pXmlDoc, aPath, "bookmark-end");
834 CPPUNIT_ASSERT_EQUAL(0, pos2);
835 CPPUNIT_ASSERT_EQUAL(1, pos3);
836 CPPUNIT_ASSERT_EQUAL(2, pos4);
839 // 1. Load document:
840 // <text:p text:style-name="Standard">
841 // <text:bookmark-start text:name="test"/>
842 // <text:bookmark-end text:name="test"/>
843 // def
844 // </text:p>
846 // 2. Call our macro
848 // Sub Main
849 // bookmark = ThisComponent.getBookmarks().getByName("test")
850 // bookmark.getAnchor().setString("abc")
851 // End Sub
853 // The text "abc" gets inserted inside the bookmark "test", and the document now contains the string "abcdef".
854 // 3. Save the document:
855 // <text:p text:style-name="Standard">
856 // <text:bookmark text:name="test"/>
857 // abcdef
858 // </text:p>
860 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testRemoveBookmarkTextAndAddNewAfterReload)
862 // load document
863 createSwDoc("collapsed_bookmark.odt");
864 SwDoc* pDoc = getSwDoc();
866 // write "abc" to area marked with "testBookmark" bookmark
868 // Get helper objects
869 uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
871 // Create cursor from bookmark
872 uno::Reference<text::XTextContent> xTextContent(
873 xBookmarksSupplier->getBookmarks()->getByName(u"test"_ustr), uno::UNO_QUERY);
874 uno::Reference<text::XTextRange> xRange = xTextContent->getAnchor();
875 CPPUNIT_ASSERT_EQUAL(u""_ustr, xRange->getString());
877 // write "abc"
878 xRange->setString(u"abc"_ustr);
880 // verify: bookmark is still exist
881 IDocumentMarkAccess& rIDMA = *pDoc->getIDocumentMarkAccess();
882 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), rIDMA.getBookmarksCount());
885 // save original document
886 save(u"writer8"_ustr);
888 // load only content.xml from the resaved document
889 xmlDocUniquePtr pXmlDoc = parseExport(u"content.xml"_ustr);
890 const char* const aPath("/office:document-content/office:body/office:text/text:p");
892 const int pos1 = getXPathPosition(pXmlDoc, aPath, "bookmark");
893 const int pos2 = getXPathPosition(pXmlDoc, aPath, "text");
895 CPPUNIT_ASSERT_EQUAL(0, pos1);
896 CPPUNIT_ASSERT_EQUAL(1, pos2);
898 CPPUNIT_ASSERT_ASSERTION_FAIL(getXPathPosition(pXmlDoc, aPath, "bookmark-start")); // not found
899 CPPUNIT_ASSERT_ASSERTION_FAIL(getXPathPosition(pXmlDoc, aPath, "bookmark-end")); // not found
902 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf96961)
904 // Insert a page break.
905 createSwDoc();
906 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
907 pWrtShell->InsertPageBreak();
909 // Enable hide whitespace mode.
910 SwViewOption aViewOptions(*pWrtShell->GetViewOptions());
911 aViewOptions.SetHideWhitespaceMode(true);
912 pWrtShell->ApplyViewOptions(aViewOptions);
914 calcLayout();
916 // Assert that the height of the last page is larger than the height of other pages.
917 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
918 sal_Int32 nOther = getXPath(pXmlDoc, "/root/page[1]/infos/bounds", "height").toInt32();
919 sal_Int32 nLast = getXPath(pXmlDoc, "/root/page[2]/infos/bounds", "height").toInt32();
920 CPPUNIT_ASSERT(nLast > nOther);
923 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf88453)
925 createSwDoc("tdf88453.odt");
926 calcLayout();
927 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
928 // This was 0: the table does not fit the first page, but it wasn't split
929 // to continue on the second page.
930 assertXPath(pXmlDoc, "/root/page[2]/body/tab", 1);
933 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf88453Table)
935 createSwDoc("tdf88453-table.odt");
936 calcLayout();
937 // This was 2: layout could not split the large outer table in the document
938 // into 3 pages.
939 CPPUNIT_ASSERT_EQUAL(3, getPages());
942 namespace
944 int checkShells(const SwDocShell* pSource, const SwDocShell* pDestination)
946 return int(SfxClassificationHelper::CheckPaste(pSource->getDocProperties(),
947 pDestination->getDocProperties()));
951 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testClassificationPaste)
953 createSwDoc();
954 SwDocShell* pSourceShell = getSwDocShell();
955 uno::Reference<lang::XComponent> xSourceComponent = mxComponent;
956 mxComponent.clear();
958 createSwDoc();
959 SwDocShell* pDestinationShell = getSwDocShell();
961 // Not classified source, not classified destination.
962 CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::None),
963 checkShells(pSourceShell, pDestinationShell));
965 // Classified source, not classified destination.
966 uno::Sequence<beans::PropertyValue> aInternalOnly
967 = comphelper::InitPropertySequence({ { "Name", uno::Any(u"Internal Only"_ustr) } });
968 dispatchCommand(xSourceComponent, u".uno:ClassificationApply"_ustr, aInternalOnly);
969 CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::TargetDocNotClassified),
970 checkShells(pSourceShell, pDestinationShell));
972 // Classified source and classified destination -- internal only has a higher level than confidential.
973 uno::Sequence<beans::PropertyValue> aConfidential
974 = comphelper::InitPropertySequence({ { "Name", uno::Any(u"Confidential"_ustr) } });
975 dispatchCommand(mxComponent, u".uno:ClassificationApply"_ustr, aConfidential);
976 CPPUNIT_ASSERT_EQUAL(int(SfxClassificationCheckPasteResult::DocClassificationTooLow),
977 checkShells(pSourceShell, pDestinationShell));
979 xSourceComponent->dispose();
982 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testSmallCaps)
984 // Create a document, add some characters and select them.
985 createSwDoc();
986 createSwDoc();
987 SwDocShell* pDocShell = getSwDocShell();
988 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
989 pWrtShell->Insert(u"text"_ustr);
990 pWrtShell->SelAll();
992 // Dispatch the command to make them formatted small capitals.
993 dispatchCommand(mxComponent, u".uno:SmallCaps"_ustr, {});
995 // This was css::style::CaseMap::NONE as the shell didn't handle the command.
996 CPPUNIT_ASSERT_EQUAL(css::style::CaseMap::SMALLCAPS,
997 getProperty<sal_Int16>(getRun(getParagraph(1), 1), u"CharCaseMap"_ustr));
1000 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf98987)
1002 createSwDoc("tdf98987.docx");
1003 calcLayout();
1004 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1005 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[2]/SdrObject", "name",
1006 u"Rectangle 1");
1007 sal_Int32 nRectangle1
1008 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[2]/bounds", "top")
1009 .toInt32();
1010 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/SdrObject", "name",
1011 u"Rectangle 2");
1012 sal_Int32 nRectangle2
1013 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/bounds", "top")
1014 .toInt32();
1015 CPPUNIT_ASSERT_GREATER(nRectangle1, nRectangle2);
1017 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[3]/SdrObject", "name",
1018 u"Rectangle 3");
1019 sal_Int32 nRectangle3
1020 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[3]/bounds", "top")
1021 .toInt32();
1022 // This failed: the 3rd rectangle had a smaller "top" value than the 2nd one, it even overlapped with the 1st one.
1023 CPPUNIT_ASSERT_GREATER(nRectangle2, nRectangle3);
1026 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf99004)
1028 createSwDoc("tdf99004.docx");
1029 calcLayout();
1030 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1031 sal_Int32 nTextbox1Top
1032 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "top").toInt32();
1033 sal_Int32 nTextBox1Height
1034 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/fly/infos/bounds", "height").toInt32();
1035 sal_Int32 nTextBox1Bottom = nTextbox1Top + nTextBox1Height;
1037 assertXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/SdrObject", "name",
1038 u"Rectangle 2");
1039 sal_Int32 nRectangle2Top
1040 = getXPath(pXmlDoc, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/bounds", "top")
1041 .toInt32();
1042 // This was 3291 and 2531, should be now around 2472 and 2531, i.e. the two rectangles should not overlap anymore.
1043 CPPUNIT_ASSERT(nTextBox1Bottom < nRectangle2Top);
1046 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf84695)
1048 createSwDoc("tdf84695.odt");
1049 SwDoc* pDoc = getSwDoc();
1050 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1051 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
1052 SdrObject* pObject = pPage->GetObj(1);
1053 SwContact* pTextBox = static_cast<SwContact*>(pObject->GetUserCall());
1054 // First, make sure that pTextBox is a fly frame (textbox of a shape).
1055 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_FLYFRMFMT), pTextBox->GetFormat()->Which());
1057 // Then select it.
1058 pWrtShell->SelectObj(Point(), 0, pObject);
1060 // Now Enter + a key should add some text.
1061 SwXTextDocument* pTextDoc = getSwTextDoc();
1062 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RETURN);
1063 emulateTyping(u"a");
1065 uno::Reference<text::XTextRange> xShape(getShape(1), uno::UNO_QUERY);
1066 // This was empty, Enter did not start the fly frame edit mode.
1067 CPPUNIT_ASSERT_EQUAL(u"a"_ustr, xShape->getString());
1070 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf84695NormalChar)
1072 createSwDoc("tdf84695.odt");
1073 SwDoc* pDoc = getSwDoc();
1074 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1075 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
1076 SdrObject* pObject = pPage->GetObj(1);
1077 SwContact* pTextBox = static_cast<SwContact*>(pObject->GetUserCall());
1078 // First, make sure that pTextBox is a fly frame (textbox of a shape).
1079 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_FLYFRMFMT), pTextBox->GetFormat()->Which());
1081 // Then select it.
1082 pWrtShell->SelectObj(Point(), 0, pObject);
1084 // Now pressing 'a' should add a character.
1085 emulateTyping(u"a");
1087 uno::Reference<text::XTextRange> xShape(getShape(1), uno::UNO_QUERY);
1088 // This was empty, pressing a normal character did not start the fly frame edit mode.
1089 CPPUNIT_ASSERT_EQUAL(u"a"_ustr, xShape->getString());
1092 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf84695Tab)
1094 createSwDoc("tdf84695-tab.odt");
1095 SwDoc* pDoc = getSwDoc();
1096 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1097 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
1098 SdrObject* pObject = pPage->GetObj(0);
1099 SwContact* pShape = static_cast<SwContact*>(pObject->GetUserCall());
1100 // First, make sure that pShape is a draw shape.
1101 CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_DRAWFRMFMT), pShape->GetFormat()->Which());
1103 // Then select it.
1104 pWrtShell->SelectObj(Point(), 0, pObject);
1106 // Now pressing 'tab' should jump to the other shape.
1107 SwXTextDocument* pTextDoc = getSwTextDoc();
1108 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
1109 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYUP, 0, KEY_TAB);
1110 Scheduler::ProcessEventsToIdle();
1112 // And finally make sure the selection has changed.
1113 const SdrMarkList& rMarkList = pWrtShell->GetDrawView()->GetMarkedObjectList();
1114 SwContact* pOtherShape
1115 = static_cast<SwContact*>(rMarkList.GetMark(0)->GetMarkedSdrObj()->GetUserCall());
1116 // This failed, 'tab' didn't do anything -> the selected shape was the same.
1117 CPPUNIT_ASSERT(pOtherShape != pShape);
1120 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTableStyleUndo)
1122 createSwDoc();
1123 SwDoc* pDoc = getSwDoc();
1124 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
1126 sal_Int32 nStyleCount = pDoc->GetTableStyles().size();
1127 SwTableAutoFormat* pStyle = pDoc->MakeTableStyle(u"Test Style"_ustr);
1128 SvxBrushItem aBackground(COL_LIGHTMAGENTA, RES_BACKGROUND);
1129 pStyle->GetBoxFormat(0).SetBackground(aBackground);
1131 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount + 1);
1132 rUndoManager.Undo();
1133 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount);
1134 rUndoManager.Redo();
1135 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount + 1);
1136 // check if attributes are preserved
1137 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1138 CPPUNIT_ASSERT(pStyle);
1139 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground));
1141 pDoc->DelTableStyle(u"Test Style"_ustr);
1142 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount);
1143 rUndoManager.Undo();
1144 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount + 1);
1145 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1146 // check if attributes are preserved
1147 CPPUNIT_ASSERT(pStyle);
1148 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground));
1149 rUndoManager.Redo();
1150 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount);
1152 // undo delete so we can replace the style
1153 rUndoManager.Undo();
1154 CPPUNIT_ASSERT_EQUAL(sal_Int32(pDoc->GetTableStyles().size()), nStyleCount + 1);
1155 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1156 CPPUNIT_ASSERT(pStyle);
1157 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground));
1159 SwTableAutoFormat aNewStyle(u"Test Style2"_ustr);
1160 SvxBrushItem aBackground2(COL_LIGHTGREEN, RES_BACKGROUND);
1161 aNewStyle.GetBoxFormat(0).SetBackground(aBackground2);
1163 pDoc->ChgTableStyle(u"Test Style"_ustr, aNewStyle);
1164 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1165 CPPUNIT_ASSERT(pStyle);
1166 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground2));
1167 rUndoManager.Undo();
1168 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1169 CPPUNIT_ASSERT(pStyle);
1170 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground));
1171 rUndoManager.Redo();
1172 pStyle = pDoc->GetTableStyles().FindAutoFormat(u"Test Style");
1173 CPPUNIT_ASSERT(pStyle);
1174 CPPUNIT_ASSERT(bool(pStyle->GetBoxFormat(0).GetBackground() == aBackground2));
1177 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testRedlineCopyPaste)
1179 // regressed in tdf#106746
1180 createSwDoc();
1181 SwDoc* pDoc = getSwDoc();
1183 SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
1184 SwPaM aPaM(aIdx);
1186 pDoc->getIDocumentContentOperations().InsertString(aPaM, u"abzdezgh"_ustr);
1187 SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
1189 // Turn on track changes, make changes, turn off track changes
1190 uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
1191 xPropertySet->setPropertyValue(u"RecordChanges"_ustr, uno::Any(true));
1192 lcl_selectCharacters(aPaM, 2, 3);
1193 pDoc->getIDocumentContentOperations().ReplaceRange(aPaM, u"c"_ustr, false);
1194 lcl_selectCharacters(aPaM, 6, 7);
1195 pDoc->getIDocumentContentOperations().ReplaceRange(aPaM, u"f"_ustr, false);
1196 xPropertySet->setPropertyValue(u"RecordChanges"_ustr, uno::Any(false));
1198 // Create the clipboard document.
1199 SwDoc aClipboard;
1200 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1202 // Select the whole content, copy, delete the original and paste the copied content
1203 pWrtShell->SelAll();
1204 pWrtShell->Copy(aClipboard);
1205 pWrtShell->Delete();
1206 pWrtShell->Paste(aClipboard);
1208 // With the bug this is "abzcdefgh", ie. contains the first deleted piece, too
1209 CPPUNIT_ASSERT_EQUAL(u"abcdefgh"_ustr, pTextNode->GetText());
1212 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf135260)
1214 createSwDoc();
1215 SwDoc* pDoc = getSwDoc();
1216 SwDocShell* pDocShell = getSwDocShell();
1217 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
1218 pWrtShell->Insert(u"test"_ustr);
1220 // Turn on track changes
1221 uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
1222 xPropertySet->setPropertyValue(u"RecordChanges"_ustr, uno::Any(true));
1224 for (int i = 0; i < 4; i++)
1226 pWrtShell->DelLeft();
1229 SwEditShell* const pEditShell(pDoc->GetEditShell());
1230 CPPUNIT_ASSERT(pEditShell);
1231 // accept all redlines
1232 while (pEditShell->GetRedlineCount())
1233 pEditShell->AcceptRedline(0);
1235 // Without the fix in place, this test would have failed with
1236 // - Expected:
1237 // - Actual : tes
1238 CPPUNIT_ASSERT_EQUAL(u""_ustr, getParagraph(1)->getString());
1241 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testRedlineParam)
1243 // Create a document with minimal content.
1244 createSwDoc();
1245 SwDoc* pDoc = getSwDoc();
1246 SwDocShell* pDocShell = getSwDocShell();
1247 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
1248 pWrtShell->Insert(u"middle"_ustr);
1250 // Turn on track changes, and add changes to the start and end of the document.
1251 uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
1252 xPropertySet->setPropertyValue(u"RecordChanges"_ustr, uno::Any(true));
1253 pWrtShell->StartOfSection();
1254 pWrtShell->Insert(u"aaa"_ustr);
1255 pWrtShell->EndOfSection();
1256 pWrtShell->Insert(u"zzz"_ustr);
1258 const SwRedlineTable& rTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
1259 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(2), rTable.size());
1261 // Select the first redline.
1262 pWrtShell->StartOfSection();
1263 uno::Sequence<beans::PropertyValue> aPropertyValues(comphelper::InitPropertySequence(
1264 { { "NextTrackedChange", uno::Any(o3tl::narrowing<sal_uInt16>(rTable[0]->GetId())) } }));
1265 dispatchCommand(mxComponent, u".uno:NextTrackedChange"_ustr, aPropertyValues);
1266 SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
1267 // This failed: the parameter wasn't handled so the next change (zzz) was
1268 // selected, not the first one (aaa).
1269 CPPUNIT_ASSERT_EQUAL(u"aaa"_ustr, pShellCursor->GetText());
1271 // Select the second redline.
1272 pWrtShell->StartOfSection();
1273 aPropertyValues = comphelper::InitPropertySequence(
1274 { { "NextTrackedChange", uno::Any(o3tl::narrowing<sal_uInt16>(rTable[1]->GetId())) } });
1275 dispatchCommand(mxComponent, u".uno:NextTrackedChange"_ustr, aPropertyValues);
1276 pShellCursor = pWrtShell->getShellCursor(false);
1277 CPPUNIT_ASSERT_EQUAL(u"zzz"_ustr, pShellCursor->GetText());
1279 // Move the cursor to the start again, and reject the second change.
1280 pWrtShell->StartOfSection();
1281 aPropertyValues = comphelper::InitPropertySequence(
1282 { { "RejectTrackedChange", uno::Any(o3tl::narrowing<sal_uInt16>(rTable[1]->GetId())) } });
1283 dispatchCommand(mxComponent, u".uno:RejectTrackedChange"_ustr, aPropertyValues);
1284 pShellCursor = pWrtShell->getShellCursor(false);
1286 // This was 'middlezzz', the uno command rejected the redline under the
1287 // cursor, instead of the requested one.
1288 CPPUNIT_ASSERT_EQUAL(u"aaamiddle"_ustr,
1289 pShellCursor->GetPoint()->GetNode().GetTextNode()->GetText());
1292 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testRedlineViewAuthor)
1294 // Test that setting an author at an SwView level has effect.
1296 // Create a document with minimal content.
1297 createSwDoc();
1298 SwDoc* pDoc = getSwDoc();
1299 SwDocShell* pDocShell = getSwDocShell();
1300 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
1301 pWrtShell->Insert(u"middle"_ustr);
1302 SwView* pView = pDocShell->GetView();
1303 static constexpr OUString aAuthor(u"A U. Thor"_ustr);
1304 pView->SetRedlineAuthor(aAuthor);
1305 pDocShell->SetView(pView);
1307 // Turn on track changes, and add changes to the start of the document.
1308 uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
1309 xPropertySet->setPropertyValue(u"RecordChanges"_ustr, uno::Any(true));
1310 pWrtShell->StartOfSection();
1311 pWrtShell->Insert(u"aaa"_ustr);
1313 // Now assert that SwView::SetRedlineAuthor() had an effect.
1314 const SwRedlineTable& rTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
1315 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), rTable.size());
1316 SwRangeRedline* pRedline = rTable[0];
1317 // This was 'Unknown Author' instead of 'A U. Thor'.
1318 CPPUNIT_ASSERT_EQUAL(aAuthor, pRedline->GetAuthorString());
1320 // Insert a comment and assert that SwView::SetRedlineAuthor() affects this as well.
1321 dispatchCommand(mxComponent, u".uno:.uno:InsertAnnotation"_ustr, {});
1322 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
1323 uno::Reference<container::XEnumerationAccess> xFieldsAccess(
1324 xTextFieldsSupplier->getTextFields());
1325 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
1326 uno::Reference<beans::XPropertySet> xField(xFields->nextElement(), uno::UNO_QUERY);
1327 // This was 'Unknown Author' instead of 'A U. Thor'.
1328 CPPUNIT_ASSERT_EQUAL(aAuthor, xField->getPropertyValue(u"Author"_ustr).get<OUString>());
1330 //Reset the redline author after using it, otherwise, it might interfere with other unittests
1331 pView->SetRedlineAuthor(u"Unknown Author"_ustr);
1332 pDocShell->SetView(pView);
1335 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf91292)
1337 createSwDoc("tdf91292_paraBackground.docx");
1338 uno::Reference<beans::XPropertySet> xPropertySet(getParagraph(1), uno::UNO_QUERY);
1339 CPPUNIT_ASSERT_EQUAL_MESSAGE("Solid background color", drawing::FillStyle_SOLID,
1340 getProperty<drawing::FillStyle>(xPropertySet, u"FillStyle"_ustr));
1341 CPPUNIT_ASSERT_EQUAL_MESSAGE("Background Color", Color(0x5C2D91),
1342 getProperty<Color>(xPropertySet, u"FillColor"_ustr));
1344 // remove background color
1345 xPropertySet->setPropertyValue(u"FillStyle"_ustr, uno::Any(drawing::FillStyle_NONE));
1347 // Save it and load it back.
1348 saveAndReload(u"Office Open XML Text"_ustr);
1350 xPropertySet.set(getParagraph(1), uno::UNO_QUERY);
1351 CPPUNIT_ASSERT_EQUAL_MESSAGE("No background color", drawing::FillStyle_NONE,
1352 getProperty<drawing::FillStyle>(xPropertySet, u"FillStyle"_ustr));
1355 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf78727)
1357 createSwDoc("tdf78727.docx");
1358 SwDoc* pDoc = getSwDoc();
1359 SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
1360 // This was 1: make sure we don't loose the TextBox anchored inside the
1361 // table that is moved inside a text frame.
1362 CPPUNIT_ASSERT(SwTextBoxHelper::getCount(pPage) > 1);
1365 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testRedlineTimestamp)
1367 // Test that a redline timestamp's second is not always 0.
1369 // Create a document with minimal content.
1370 createSwDoc();
1371 SwDoc* pDoc = getSwDoc();
1372 SwDocShell* pDocShell = getSwDocShell();
1373 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
1374 pWrtShell->Insert(u"middle"_ustr);
1376 // Turn on track changes, and add changes to the start and to the end of
1377 // the document.
1378 uno::Reference<beans::XPropertySet> xPropertySet(mxComponent, uno::UNO_QUERY);
1379 xPropertySet->setPropertyValue(u"RecordChanges"_ustr, uno::Any(true));
1380 pWrtShell->StartOfSection();
1381 pWrtShell->Insert(u"aaa"_ustr);
1382 osl::Thread::wait(std::chrono::seconds(1));
1383 pWrtShell->EndOfSection();
1384 pWrtShell->Insert(u"zzz"_ustr);
1386 // Inserting additional characters at the start changed the table size to
1387 // 3, i.e. the first and the second "aaa" wasn't combined.
1388 pWrtShell->StartOfSection();
1389 pWrtShell->Insert(u"aaa"_ustr);
1391 // Now assert that at least one of the seconds are not 0.
1392 const SwRedlineTable& rTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
1393 if (rTable.size() >= 2
1394 && rTable[0]->GetRedlineData().GetTimeStamp().GetMin()
1395 != rTable[1]->GetRedlineData().GetTimeStamp().GetMin())
1396 // The relatively rare case when waiting for a second also changes the minute.
1397 return;
1399 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(2), rTable.size());
1400 sal_uInt16 nSec1 = rTable[0]->GetRedlineData().GetTimeStamp().GetSec();
1401 sal_uInt16 nSec2 = rTable[1]->GetRedlineData().GetTimeStamp().GetSec();
1402 // This failed, seconds was always 0.
1403 CPPUNIT_ASSERT(nSec1 != 0 || nSec2 != 0);
1406 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testCursorWindows)
1408 // Create a new document with one window.
1409 createSwDoc();
1410 SwDocShell* pDocShell = getSwDocShell();
1411 SwWrtShell* pWrtShell1 = pDocShell->GetWrtShell();
1413 // Create a second view and type something.
1414 pDocShell->GetViewShell()->GetViewFrame().GetDispatcher()->Execute(
1415 SID_NEWWINDOW, SfxCallMode::SYNCHRON | SfxCallMode::RECORD);
1416 SwWrtShell* pWrtShell2 = pDocShell->GetWrtShell();
1417 OUString aText(u"foo"_ustr);
1418 pWrtShell2->Insert(aText);
1420 // Assert that only the cursor of the actual window move, not other cursors.
1421 SwShellCursor* pShellCursor1 = pWrtShell1->getShellCursor(false);
1422 SwShellCursor* pShellCursor2 = pWrtShell2->getShellCursor(false);
1423 // This was 3, not 0 -- cursor of the other window moved.
1424 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(0), pShellCursor1->Start()->GetContentIndex());
1425 CPPUNIT_ASSERT_EQUAL(aText.getLength(), pShellCursor2->Start()->GetContentIndex());
1428 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testLandscape)
1430 // Set page orientation to landscape.
1431 createSwDoc();
1432 uno::Sequence<beans::PropertyValue> aPropertyValues(
1433 comphelper::InitPropertySequence({ { "AttributePage.Landscape", uno::Any(true) } }));
1434 dispatchCommand(mxComponent, u".uno:AttributePage"_ustr, aPropertyValues);
1436 // Assert that the document model was modified.
1437 SwDocShell* pDocShell = getSwDocShell();
1438 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
1439 size_t nPageDesc = pWrtShell->GetCurPageDesc();
1440 // This failed, page was still portrait.
1441 CPPUNIT_ASSERT(pWrtShell->GetPageDesc(nPageDesc).GetLandscape());
1444 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf95699)
1446 // Open the document with single FORMCHECKBOX field, select all and copy to clipboard
1447 // then check that clipboard contains the FORMCHECKBOX in text body.
1448 // Previously that failed.
1449 createSwDoc("tdf95699.odt");
1450 SwDoc* pDoc = getSwDoc();
1451 IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
1452 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount());
1453 SwDoc aClipboard;
1454 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1455 pWrtShell->SelAll();
1456 pWrtShell->Copy(aClipboard);
1457 pMarkAccess = aClipboard.getIDocumentMarkAccess();
1458 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), pMarkAccess->getAllMarksCount());
1459 ::sw::mark::Fieldmark* pFieldMark
1460 = pMarkAccess->getFieldmarkAfter(SwPosition(aClipboard.GetNodes().GetEndOfExtras()), false);
1461 CPPUNIT_ASSERT_EQUAL(u"vnd.oasis.opendocument.field.FORMCHECKBOX"_ustr,
1462 pFieldMark->GetFieldname());
1465 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf151548_tabNavigation2)
1467 // given a form-protected doc with 2 unchecked legacy fieldmark checkboxes, 1 modern
1468 // checkbox, and a couple of other content controls that are not supposed to
1469 // have their contents selected upon entry into the control (i.e. no placeholder text).
1470 createSwDoc("tdf151548_tabNavigation2.docx");
1471 SwDoc* pDoc = getSwDoc();
1473 IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
1474 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), pMarkAccess->getFieldmarksCount());
1476 // verify that the checkboxes start off in the unchecked state
1477 for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
1479 sw::mark::CheckboxFieldmark* pCheckBox = dynamic_cast<::sw::mark::CheckboxFieldmark*>(*it);
1480 CPPUNIT_ASSERT(!pCheckBox->IsChecked());
1483 // Toggle on the legacy checkbox
1484 SwXTextDocument* pTextDoc = getSwTextDoc();
1485 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 32, KEY_SPACE);
1486 // Tab to the next control - the modern checkbox
1487 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
1488 // Tab to the next control - the second legacy checkbox, and toggle it on.
1489 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
1490 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 32, KEY_SPACE);
1491 // Tab to the next control - a plain text control without placeholder text
1492 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
1493 // Tab to the next control - a combobox with custom text
1494 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
1495 Scheduler::ProcessEventsToIdle();
1497 for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
1499 sw::mark::CheckboxFieldmark* pCheckBox = dynamic_cast<::sw::mark::CheckboxFieldmark*>(*it);
1500 // verify that the legacy checkbox became checked by the first loop.
1501 CPPUNIT_ASSERT(pCheckBox->IsChecked());
1503 // This is where it was failing. Tab got stuck moving into the plain text/combobox,
1504 // so it could never loop around. At this point we are at the end of the loop,
1505 // so the next tab should take us back to the beginning with the first legacy checkbox.
1507 // Tab to the legacy checkbox, and toggle it off.
1508 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
1509 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 32, KEY_SPACE);
1510 Scheduler::ProcessEventsToIdle();
1511 CPPUNIT_ASSERT(!pCheckBox->IsChecked());
1513 // Tab to the next content control
1514 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB);
1518 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf151548_tabNavigation)
1520 // given a form-protected doc with 4 unchecked legacy fieldmark checkboxes (and several modern
1521 // content controls which all have a tabstop of -1 to disable tabstop navigation to them)
1522 // we want to test that tab navigation completes and loops around to continue at the beginning.
1523 createSwDoc("tdf151548_tabNavigation.docm");
1524 SwDoc* pDoc = getSwDoc();
1526 IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
1527 CPPUNIT_ASSERT_EQUAL(sal_Int32(4), pMarkAccess->getFieldmarksCount());
1529 SwXTextDocument* pTextDoc = getSwTextDoc();
1530 // Tab and toggle 4 times, verifying beforehand that the state was unchecked
1531 for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
1533 sw::mark::CheckboxFieldmark* pCheckBox = dynamic_cast<::sw::mark::CheckboxFieldmark*>(*it);
1534 CPPUNIT_ASSERT(!pCheckBox->IsChecked());
1536 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 32, KEY_SPACE); // toggle checkbox on
1537 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); // move to next control
1538 Scheduler::ProcessEventsToIdle();
1541 // Tab 4 more times, verifying beforehand that the checkbox had been toggle on, then toggles off
1542 // meaning that looping is working, and no other controls are reacting to the tab key.
1543 for (auto it = pMarkAccess->getFieldmarksBegin(); it != pMarkAccess->getFieldmarksEnd(); ++it)
1545 sw::mark::CheckboxFieldmark* pCheckBox = dynamic_cast<::sw::mark::CheckboxFieldmark*>(*it);
1547 CPPUNIT_ASSERT(pCheckBox->IsChecked());
1548 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 32, KEY_SPACE); // toggle checkbox off
1549 Scheduler::ProcessEventsToIdle();
1551 CPPUNIT_ASSERT(!pCheckBox->IsChecked());
1552 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_TAB); // move to next control
1556 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf104032)
1558 // Open the document with FORMCHECKBOX field, select it and copy to clipboard
1559 // Go to end of document and paste it, then undo
1560 // Previously that asserted in debug build.
1561 createSwDoc("tdf104032.odt");
1562 SwDoc* pDoc = getSwDoc();
1563 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
1564 SwDoc aClipboard;
1565 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1566 pWrtShell->StartOfSection();
1567 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
1568 pWrtShell->Copy(aClipboard);
1569 pWrtShell->EndOfSection();
1570 pWrtShell->Paste(aClipboard);
1571 rUndoManager.Undo();
1574 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf104440)
1576 createSwDoc("tdf104440.odt");
1577 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1578 // This was 0: both Text Frames in the document were anchored to a
1579 // paragraph on page 1, while we expect that the second Text Frame is
1580 // anchored to a paragraph on page 2.
1581 assertXPath(pXmlDoc, "//page[2]/body/txt/anchored");
1584 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf104425)
1586 createSwDoc("tdf104425.odt");
1587 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1588 // The document contains one top-level 1-cell table with minimum row height set to 70 cm,
1589 // and the cell contents does not exceed the minimum row height.
1590 // It should span over 3 pages.
1591 assertXPath(pXmlDoc, "//page", 3);
1592 sal_Int32 nHeight1
1593 = getXPath(pXmlDoc, "//page[1]/body/tab/row/infos/bounds", "height").toInt32();
1594 sal_Int32 nHeight2
1595 = getXPath(pXmlDoc, "//page[2]/body/tab/row/infos/bounds", "height").toInt32();
1596 sal_Int32 nHeight3
1597 = getXPath(pXmlDoc, "//page[3]/body/tab/row/infos/bounds", "height").toInt32();
1598 double fSumHeight_mm = o3tl::convert<double>(nHeight1 + nHeight2 + nHeight3, o3tl::Length::twip,
1599 o3tl::Length::mm);
1600 CPPUNIT_ASSERT_DOUBLES_EQUAL(700.0, fSumHeight_mm, 0.05);
1603 // accepting change tracking gets stuck on change
1604 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf104814)
1606 createSwDoc("tdf104814.docx");
1607 SwDoc* pDoc = getSwDoc();
1609 SwEditShell* const pEditShell(pDoc->GetEditShell());
1610 CPPUNIT_ASSERT(pEditShell);
1612 // accept all redlines
1613 while (pEditShell->GetRedlineCount())
1614 pEditShell->AcceptRedline(0);
1617 // crash at redo of accepting table change tracking imported from DOCX
1618 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTableRedlineRedoCrash)
1620 createSwDoc("TC-table-del-add.docx");
1621 SwDoc* pDoc = getSwDoc();
1622 sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
1624 // accept all redlines, Undo and accept all redlines again
1626 IDocumentRedlineAccess& rIDRA(pDoc->getIDocumentRedlineAccess());
1627 rIDRA.AcceptAllRedline(/*bAccept=*/true);
1629 rUndoManager.Undo();
1631 // without the fix, it crashes
1632 rIDRA.AcceptAllRedline(true);
1635 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTableRemoveHasTextChangesOnly)
1637 createSwDoc("TC-table-del-add.docx");
1638 SwDoc* pDoc = getSwDoc();
1639 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1640 CPPUNIT_ASSERT(pWrtShell);
1642 // disable Record Changes
1643 dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
1644 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
1645 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1647 // 4 rows in Show Changes mode
1648 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1649 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1651 // Accepting tracked deletions results 3 rows
1652 IDocumentRedlineAccess& rIDRA(pDoc->getIDocumentRedlineAccess());
1653 rIDRA.AcceptAllRedline(/*bAccept=*/true);
1654 Scheduler::ProcessEventsToIdle();
1655 pXmlDoc = parseLayoutDump();
1656 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3);
1658 // Undo: 4 rows again
1659 pDoc->GetIDocumentUndoRedo().Undo();
1660 pXmlDoc = parseLayoutDump();
1661 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1663 // Accepting again: 3 rows (Undo of HasTextChangesOnly is correct)
1664 rIDRA.AcceptAllRedline(/*bAccept=*/true);
1665 Scheduler::ProcessEventsToIdle();
1666 pXmlDoc = parseLayoutDump();
1667 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3);
1669 // Undo: 4 rows again
1670 pDoc->GetIDocumentUndoRedo().Undo();
1671 pXmlDoc = parseLayoutDump();
1672 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1674 // Move the cursor after the redline, and insert some text without change tracking
1675 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1676 pWrtShell->Insert(u"X"_ustr);
1678 // Accepting again: 4 rows (extra text keeps the deleted row)
1679 rIDRA.AcceptAllRedline(/*bAccept=*/true);
1680 Scheduler::ProcessEventsToIdle();
1681 pXmlDoc = parseLayoutDump();
1682 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1684 // delete the extra text with change tracking:
1685 // this resulted tracked row deletion again, because of missing
1686 // removing of HasTextChangeOnly SwTabLine property at accepting deletions previously
1688 // disable Record Changes
1689 dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
1690 CPPUNIT_ASSERT_MESSAGE("redlining should be on",
1691 pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1693 dispatchCommand(mxComponent, u".uno:SwBackSpace"_ustr, {});
1694 rIDRA.AcceptAllRedline(/*bAccept=*/true);
1695 Scheduler::ProcessEventsToIdle();
1696 pXmlDoc = parseLayoutDump();
1697 // This was 3
1698 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1701 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTableRemoveHasTextChangesOnly2)
1703 createSwDoc("TC-table-del-add.docx");
1704 SwDoc* pDoc = getSwDoc();
1705 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1706 CPPUNIT_ASSERT(pWrtShell);
1708 // disable Record Changes
1709 dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
1710 CPPUNIT_ASSERT_MESSAGE("redlining should be off",
1711 !pDoc->getIDocumentRedlineAccess().IsRedlineOn());
1713 // check redline count
1714 SwEditShell* const pEditShell(pDoc->GetEditShell());
1715 CPPUNIT_ASSERT(pEditShell);
1716 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1718 // 4 rows in Show Changes mode
1719 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1720 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1722 // Move the cursor to the tracked insertion, after the first redline to activate the
1723 // acception of the whole table row insertion with a single "Accept Change"
1724 pWrtShell->Down(/*bSelect=*/false);
1725 pWrtShell->Down(/*bSelect=*/false);
1726 pWrtShell->Down(/*bSelect=*/false);
1727 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
1728 Scheduler::ProcessEventsToIdle();
1729 dispatchCommand(mxComponent, u".uno:AcceptTrackedChange"_ustr, {});
1730 pXmlDoc = parseLayoutDump();
1731 // Accepting tracked insertion results still 4 rows, but less redlines
1732 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1733 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(11), pEditShell->GetRedlineCount());
1735 // Undo: 4 rows again
1736 pDoc->GetIDocumentUndoRedo().Undo();
1737 pXmlDoc = parseLayoutDump();
1738 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1739 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1741 // To check Undo of HasTextChangesOnly reject the same row results 3 rows
1742 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
1743 dispatchCommand(mxComponent, u".uno:RejectTrackedChange"_ustr, {});
1744 pXmlDoc = parseLayoutDump();
1745 // This was 4 (lost HasTextChangesOnly)
1746 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3);
1748 // Undo: 4 rows again
1749 pDoc->GetIDocumentUndoRedo().Undo();
1750 pXmlDoc = parseLayoutDump();
1751 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1752 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1755 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf147182_AcceptAllChangesInTableSelection)
1757 createSwDoc("TC-table-del-add.docx");
1758 SwDoc* pDoc = getSwDoc();
1759 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1760 CPPUNIT_ASSERT(pWrtShell);
1762 // check redline count
1763 SwEditShell* const pEditShell(pDoc->GetEditShell());
1764 CPPUNIT_ASSERT(pEditShell);
1765 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1767 // 4 rows in Show Changes mode
1768 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1769 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1771 // Select the first table to get a table selection
1772 dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
1773 dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
1774 dispatchCommand(mxComponent, u".uno:AcceptTrackedChange"_ustr, {});
1775 pXmlDoc = parseLayoutDump();
1776 // Accepting tracked changes in the selected table results 3 rows
1777 // This was 4 (only text changes of the first selected cell were accepted)
1778 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3);
1779 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(8), pEditShell->GetRedlineCount());
1781 // Undo: 4 rows again
1782 pDoc->GetIDocumentUndoRedo().Undo();
1783 pXmlDoc = parseLayoutDump();
1784 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1785 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1787 // To check Undo of HasTextChangesOnly reject the same row results 3 rows
1788 dispatchCommand(mxComponent, u".uno:Escape"_ustr, {});
1789 dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
1790 dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
1791 dispatchCommand(mxComponent, u".uno:RejectTrackedChange"_ustr, {});
1792 pXmlDoc = parseLayoutDump();
1793 // This was 4 (only text changes of the first selected cell were rejected)
1794 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 3);
1796 // Undo: 4 rows again
1797 pDoc->GetIDocumentUndoRedo().Undo();
1798 pXmlDoc = parseLayoutDump();
1799 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row", 4);
1800 CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(14), pEditShell->GetRedlineCount());
1803 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf66405)
1805 // Imported formula should have zero margins
1806 createSwDoc("tdf66405.docx");
1807 uno::Reference<text::XTextEmbeddedObjectsSupplier> xEmbeddedObjectsSupplier(mxComponent,
1808 uno::UNO_QUERY);
1809 uno::Reference<container::XNameAccess> xEmbeddedObjects
1810 = xEmbeddedObjectsSupplier->getEmbeddedObjects();
1811 uno::Reference<beans::XPropertySet> xFormula;
1812 xEmbeddedObjects->getByName(xEmbeddedObjects->getElementNames()[0]) >>= xFormula;
1813 uno::Reference<beans::XPropertySet> xComponent;
1814 xFormula->getPropertyValue(u"Component"_ustr) >>= xComponent;
1816 // Test embedded object's margins
1817 sal_Int32 nLeftMargin, nRightMargin, nTopMargin, nBottomMargin;
1818 xFormula->getPropertyValue(u"LeftMargin"_ustr) >>= nLeftMargin;
1819 xFormula->getPropertyValue(u"RightMargin"_ustr) >>= nRightMargin;
1820 xFormula->getPropertyValue(u"TopMargin"_ustr) >>= nTopMargin;
1821 xFormula->getPropertyValue(u"BottomMargin"_ustr) >>= nBottomMargin;
1822 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nLeftMargin);
1823 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nRightMargin);
1824 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nTopMargin);
1825 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nBottomMargin);
1827 // Test embedded object component's margins
1828 xComponent->getPropertyValue(u"LeftMargin"_ustr) >>= nLeftMargin;
1829 xComponent->getPropertyValue(u"RightMargin"_ustr) >>= nRightMargin;
1830 xComponent->getPropertyValue(u"TopMargin"_ustr) >>= nTopMargin;
1831 xComponent->getPropertyValue(u"BottomMargin"_ustr) >>= nBottomMargin;
1832 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nLeftMargin);
1833 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nRightMargin);
1834 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nTopMargin);
1835 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nBottomMargin);
1838 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf35021_tabOverMarginDemo)
1840 #if HAVE_MORE_FONTS
1841 createSwDoc("tdf35021_tabOverMarginDemo.doc");
1842 calcLayout();
1843 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1844 // Tabs should go past the margin @ ~3381
1845 sal_Int32 nMargin = getXPath(pXmlDoc, "//body/txt[1]/infos/prtBounds", "width").toInt32();
1846 // left tab was 3381 because it got its own full line
1847 sal_Int32 nWidth
1848 = getXPath(pXmlDoc, "//SwFixPortion[@type='PortionType::TabLeft']", "width").toInt32();
1849 CPPUNIT_ASSERT_MESSAGE("Left Tab width is ~4479", nMargin < nWidth);
1850 // center tab was 842
1851 nWidth = getXPath(pXmlDoc, "//SwFixPortion[@type='PortionType::TabCenter']", "width").toInt32();
1852 CPPUNIT_ASSERT_MESSAGE("Center Tab width is ~3521", nMargin < nWidth);
1853 // right tab was probably the same as center tab.
1854 nWidth = getXPath(pXmlDoc, "//SwFixPortion[@type='PortionType::TabRight']", "width").toInt32();
1855 CPPUNIT_ASSERT_MESSAGE("Right Tab width is ~2907", sal_Int32(2500) < nWidth);
1856 // decimal tab was 266
1857 nWidth
1858 = getXPath(pXmlDoc, "//SwFixPortion[@type='PortionType::TabDecimal']", "width").toInt32();
1859 CPPUNIT_ASSERT_MESSAGE("Decimal Tab width is ~4096", nMargin < nWidth);
1860 #endif
1863 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf106701_tabOverMarginAutotab)
1865 createSwDoc("tdf106701_tabOverMarginAutotab.doc");
1866 calcLayout();
1867 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1868 // The right margin is ~3378
1869 sal_Int32 nRightMargin = getXPath(pXmlDoc, "//body/txt[1]/infos/prtBounds", "width").toInt32();
1870 // Automatic tabstops should never be affected by tabOverMargin compatibility
1871 // The 1st line's width previously was ~9506
1872 sal_Int32 nWidth = getXPath(pXmlDoc, "//SwParaPortion/SwLineLayout[1]", "width").toInt32();
1873 CPPUNIT_ASSERT_MESSAGE("1st line's width is less than the right margin", nWidth < nRightMargin);
1876 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf104492)
1878 createSwDoc("tdf104492.docx");
1879 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1880 // The document should split table over 3 pages.
1881 assertXPath(pXmlDoc, "//page", 3);
1884 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf107025)
1886 // Tdf107025 - characters advance with wrong distance, so that
1887 // they are cluttered because of negative value or
1888 // break into multiple lines because of overflow.
1889 // The test document uses DFKAI-SB shipped with Windows.
1890 createSwDoc("tdf107025.odt");
1891 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1892 // Verify the number of characters in each line.
1893 CPPUNIT_ASSERT_EQUAL(sal_Int32(1),
1894 getXPath(pXmlDoc, "(//SwLinePortion)[1]", "length").toInt32());
1895 CPPUNIT_ASSERT_EQUAL(sal_Int32(9),
1896 getXPath(pXmlDoc, "(//SwLinePortion)[2]", "length").toInt32());
1898 // Do the subsequent test only if the first line can be displayed,
1899 // in case that the required font does not exist.
1900 sal_Int32 nWidth1 = getXPath(pXmlDoc, "(//SwLinePortion)[1]", "width").toInt32();
1901 if (!nWidth1)
1902 return;
1904 CPPUNIT_ASSERT(!getXPath(pXmlDoc, "(//SwLinePortion)[2]", "width").isEmpty());
1905 sal_Int32 nWidth2 = getXPath(pXmlDoc, "(//SwLinePortion)[2]", "width").toInt32();
1906 sal_Int32 nRatio = nWidth2 / nWidth1;
1908 CPPUNIT_ASSERT(nRatio >= 9); // Occupy at least 9 cells.
1909 CPPUNIT_ASSERT(nRatio < 18); // Occupy at most 18 cells.
1912 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf107362)
1914 createSwDoc("tdf107362.odt");
1915 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
1916 sal_Int32 nHeight
1917 = getXPath(pXmlDoc, "(//SwParaPortion/SwLineLayout/child::*[@type='PortionType::Text'])[1]",
1918 "height")
1919 .toInt32();
1920 sal_Int32 nWidth1
1921 = getXPath(pXmlDoc, "(//SwParaPortion/SwLineLayout/child::*[@type='PortionType::Text'])[1]",
1922 "width")
1923 .toInt32();
1924 sal_Int32 nWidth2
1925 = getXPath(pXmlDoc, "(//SwParaPortion/SwLineLayout/child::*[@type='PortionType::Text'])[2]",
1926 "width")
1927 .toInt32();
1928 sal_Int32 nLineWidth = getXPath(pXmlDoc, "//SwParaPortion/SwLineLayout", "width").toInt32();
1929 sal_Int32 nKernWidth = nLineWidth - nWidth1 - nWidth2;
1930 // Test only if fonts are available
1931 if (nWidth1 > 500 && nWidth2 > 200)
1933 // Kern width should be smaller than 1/3 of the CJK font height.
1934 CPPUNIT_ASSERT(nKernWidth * 3 < nHeight);
1938 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf105417)
1940 createSwDoc("tdf105417.odt");
1941 SwView* pView = getSwDocShell()->GetView();
1942 CPPUNIT_ASSERT(pView);
1943 uno::Reference<linguistic2::XHyphenator> xHyphenator = LinguMgr::GetHyphenator();
1944 CPPUNIT_ASSERT(xHyphenator.is());
1945 // If there are no English hyphenation rules installed, we can't test
1946 // hyphenation.
1947 if (!xHyphenator->hasLocale(lang::Locale(u"en"_ustr, u"US"_ustr, OUString())))
1948 return;
1950 uno::Reference<linguistic2::XLinguProperties> xLinguProperties(LinguMgr::GetLinguPropertySet());
1951 // Automatic hyphenation means not opening a dialog, but going ahead
1952 // non-interactively.
1953 xLinguProperties->setIsHyphAuto(true);
1954 SwHyphWrapper aWrap(pView, xHyphenator, /*bStart=*/false, /*bOther=*/true,
1955 /*bSelection=*/false);
1956 // This never returned, it kept trying to hyphenate the last word
1957 // (greenbacks) again and again.
1958 aWrap.SpellDocument();
1961 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf105625)
1963 createSwDoc("tdf105625.fodt");
1964 SwDoc* pDoc = getSwDoc();
1965 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
1966 // Ensure correct initial setting
1967 std::shared_ptr<comphelper::ConfigurationChanges> batch(
1968 comphelper::ConfigurationChanges::create());
1969 officecfg::Office::Writer::Cursor::Option::IgnoreProtectedArea::set(false, batch);
1970 batch->commit();
1971 // We should be able to edit at positions adjacent to fields.
1972 // Check if the start and the end of the 1st paragraph are not protected
1973 // (they are adjacent to FORMCHECKBOX)
1974 pWrtShell->SttPara();
1975 CPPUNIT_ASSERT_EQUAL(false, pWrtShell->HasReadonlySel());
1976 pWrtShell->EndPara();
1977 CPPUNIT_ASSERT_EQUAL(false, pWrtShell->HasReadonlySel());
1978 // 2nd paragraph - FORMTEXT
1979 pWrtShell->Down(/*bSelect=*/false);
1980 // Check selection across FORMTEXT field boundary - must be read-only
1981 pWrtShell->SttPara();
1982 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 1, /*bBasicCall=*/false);
1983 CPPUNIT_ASSERT_EQUAL(true, pWrtShell->HasReadonlySel());
1984 // Test deletion of whole field with single backspace
1985 // Previously it only removed right boundary of FORMTEXT, or failed removal at all
1986 const IDocumentMarkAccess* pMarksAccess = pDoc->getIDocumentMarkAccess();
1987 sal_Int32 nMarksBefore = pMarksAccess->getAllMarksCount();
1988 pWrtShell->EndPara();
1989 pWrtShell->DelLeft();
1990 sal_Int32 nMarksAfter = pMarksAccess->getAllMarksCount();
1991 CPPUNIT_ASSERT_EQUAL(nMarksBefore, nMarksAfter + 1);
1994 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf125151_protected)
1996 // Similar to testTdf105625 except this is in a protected section,
1997 // so read-only is already true when fieldmarks are considered.
1998 createSwDoc("tdf125151_protected.fodt");
1999 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2000 // Ensure correct initial setting
2001 std::shared_ptr<comphelper::ConfigurationChanges> batch(
2002 comphelper::ConfigurationChanges::create());
2003 officecfg::Office::Writer::Cursor::Option::IgnoreProtectedArea::set(false, batch);
2004 batch->commit();
2005 pWrtShell->Down(/*bSelect=*/false);
2006 // The cursor moved inside of the FieldMark textbox.
2007 CPPUNIT_ASSERT_EQUAL_MESSAGE("Readonly 1", false, pWrtShell->HasReadonlySel());
2008 // Move left to the start/definition of the textbox
2009 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
2010 CPPUNIT_ASSERT_EQUAL_MESSAGE("Readonly 2", true, pWrtShell->HasReadonlySel());
2013 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf125151_protectedB)
2015 // Similar to testTdf105625 except this is protected with the Protect_Form compat setting
2016 createSwDoc("tdf125151_protectedB.fodt");
2017 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2018 // Ensure correct initial setting
2019 std::shared_ptr<comphelper::ConfigurationChanges> batch(
2020 comphelper::ConfigurationChanges::create());
2021 officecfg::Office::Writer::Cursor::Option::IgnoreProtectedArea::set(false, batch);
2022 batch->commit();
2023 // The cursor starts inside of the FieldMark textbox.
2024 CPPUNIT_ASSERT_EQUAL_MESSAGE("Readonly 1", false, pWrtShell->HasReadonlySel());
2025 // Move left to the start/definition of the textbox
2026 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
2027 CPPUNIT_ASSERT_EQUAL_MESSAGE("Readonly 2", true, pWrtShell->HasReadonlySel());
2030 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf106736)
2032 createSwDoc("tdf106736-grid.odt");
2033 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2034 sal_Int32 nWidth
2035 = getXPath(pXmlDoc,
2036 "(//SwParaPortion/SwLineLayout/child::*[@type='PortionType::TabLeft'])[1]",
2037 "width")
2038 .toInt32();
2039 // In tdf106736, width of tab overflow so that it got
2040 // width value around 9200, expected value is around 103
2041 CPPUNIT_ASSERT_MESSAGE("Left Tab width is ~103", nWidth < 150);
2044 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testMsWordCompTrailingBlanks)
2046 // The option is true in settings.xml
2047 createSwDoc("MsWordCompTrailingBlanksTrue.odt");
2048 SwDoc* pDoc = getSwDoc();
2049 CPPUNIT_ASSERT_EQUAL(true, pDoc->getIDocumentSettingAccess().get(
2050 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS));
2051 calcLayout();
2052 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2053 // Check that trailing spaces spans are put into Hole portion if option is enabled
2055 assertXPath(pXmlDoc, "/root/page/body/txt", 3);
2057 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*", 4);
2058 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[1]", "type",
2059 u"PortionType::Text");
2060 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[1]", "portion",
2061 u"TEST ");
2062 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[2]", "type",
2063 u"PortionType::Text");
2064 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[2]", "portion",
2065 u" ");
2066 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[3]", "type",
2067 u"PortionType::Text");
2068 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[3]", "portion",
2069 u" T");
2070 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[4]", "type",
2071 u"PortionType::Hole");
2072 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[4]", "portion",
2073 u" "); // All the trailing blanks
2075 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*", 4);
2076 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[1]", "type",
2077 u"PortionType::Text");
2078 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[1]", "portion",
2079 u"TEST ");
2080 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[2]", "type",
2081 u"PortionType::Text");
2082 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[2]", "portion",
2083 u" ");
2084 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[3]", "type",
2085 u"PortionType::Text");
2086 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[3]", "portion",
2087 u" T");
2088 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[4]", "type",
2089 u"PortionType::Hole");
2090 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[4]", "portion",
2091 u" "); // All the trailing blanks
2093 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*", 4);
2094 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[1]", "type",
2095 u"PortionType::Text");
2096 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[1]", "portion",
2097 u"TEST ");
2098 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[2]", "type",
2099 u"PortionType::Text");
2100 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[2]", "portion",
2101 u" ");
2102 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[3]", "type",
2103 u"PortionType::Text");
2104 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[3]", "portion",
2105 u" T");
2106 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[4]", "type",
2107 u"PortionType::Hole");
2108 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[4]", "portion",
2109 u" "); // All the trailing blanks
2111 // The option is false in settings.xml
2112 createSwDoc("MsWordCompTrailingBlanksFalse.odt");
2113 pDoc = getSwDoc();
2114 CPPUNIT_ASSERT_EQUAL(false, pDoc->getIDocumentSettingAccess().get(
2115 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS));
2116 calcLayout();
2117 pXmlDoc = parseLayoutDump();
2118 // Check that trailing spaces spans are put into Text portions if option is disabled
2120 assertXPath(pXmlDoc, "/root/page/body/txt", 3);
2122 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*", 5);
2123 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[1]", "type",
2124 u"PortionType::Text");
2125 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[1]", "portion",
2126 u"TEST ");
2127 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[2]", "type",
2128 u"PortionType::Text");
2129 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[2]", "portion",
2130 u" ");
2131 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[3]", "type",
2132 u"PortionType::Text");
2133 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[3]", "portion",
2134 u" T "); // first colored trailing blank span here
2135 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[4]", "type",
2136 u"PortionType::Text");
2137 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[4]", "portion",
2138 u" "); // second colored trailing blank span here
2139 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[5]", "type",
2140 u"PortionType::Text");
2141 assertXPath(pXmlDoc, "/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[5]", "portion",
2142 u" "); // third colored trailing blank span here
2144 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*", 5);
2145 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[1]", "type",
2146 u"PortionType::Text");
2147 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[1]", "portion",
2148 u"TEST ");
2149 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[2]", "type",
2150 u"PortionType::Text");
2151 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[2]", "portion",
2152 u" ");
2153 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[3]", "type",
2154 u"PortionType::Text");
2155 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[3]", "portion",
2156 u" T "); // first colored trailing blank span here
2157 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[4]", "type",
2158 u"PortionType::Text");
2159 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[4]", "portion",
2160 u" "); // second colored trailing blank span here
2161 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[5]", "type",
2162 u"PortionType::Text");
2163 assertXPath(pXmlDoc, "/root/page/body/txt[2]/SwParaPortion/SwLineLayout/child::*[5]", "portion",
2164 u" "); // third colored trailing blank span here
2166 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*", 5);
2167 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[1]", "type",
2168 u"PortionType::Text");
2169 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[1]", "portion",
2170 u"TEST ");
2171 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[2]", "type",
2172 u"PortionType::Text");
2173 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[2]", "portion",
2174 u" ");
2175 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[3]", "type",
2176 u"PortionType::Text");
2177 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[3]", "portion",
2178 u" T "); // first colored trailing blank span here
2179 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[4]", "type",
2180 u"PortionType::Text");
2181 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[4]", "portion",
2182 u" "); // second colored trailing blank span here
2183 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[5]", "type",
2184 u"PortionType::Text");
2185 assertXPath(pXmlDoc, "/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[5]", "portion",
2186 u" "); // third colored trailing blank span here
2188 // MsWordCompTrailingBlanks option should be false by default in new documents
2189 createSwDoc();
2190 pDoc = getSwDoc();
2191 CPPUNIT_ASSERT_EQUAL(false, pDoc->getIDocumentSettingAccess().get(
2192 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS));
2194 // The option should be true if a .docx, .doc or .rtf document is opened
2195 createSwDoc("MsWordCompTrailingBlanks.docx");
2196 pDoc = getSwDoc();
2197 CPPUNIT_ASSERT_EQUAL(true, pDoc->getIDocumentSettingAccess().get(
2198 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS));
2201 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testCreateDocxAnnotation)
2203 createSwDoc();
2205 // insert an annotation with a text
2206 static constexpr OUString aSomeText(u"some text"_ustr);
2207 uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({
2208 { "Text", uno::Any(aSomeText) },
2209 { "Author", uno::Any(u"me"_ustr) },
2211 dispatchCommand(mxComponent, u".uno:InsertAnnotation"_ustr, aPropertyValues);
2213 // Save it as DOCX & load it again
2214 saveAndReload(u"Office Open XML Text"_ustr);
2216 // get the annotation
2217 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
2218 uno::Reference<container::XEnumerationAccess> xFieldsAccess(
2219 xTextFieldsSupplier->getTextFields());
2220 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
2221 uno::Reference<beans::XPropertySet> xField(xFields->nextElement(), uno::UNO_QUERY);
2223 // this was empty instead of "some text"
2224 CPPUNIT_ASSERT_EQUAL(aSomeText, xField->getPropertyValue(u"Content"_ustr).get<OUString>());
2227 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf107976)
2229 // Create a document and create two transferables.
2230 createSwDoc();
2231 SwWrtShell& rShell = *getSwDocShell()->GetWrtShell();
2232 rtl::Reference<SwTransferable> pTransferable(new SwTransferable(rShell));
2233 rtl::Reference<SwTransferable> pTransferable2(new SwTransferable(rShell));
2234 // Now close the document.
2235 mxComponent->dispose();
2236 mxComponent.clear();
2237 // This failed: the first shell had a pointer to the deleted shell.
2238 CPPUNIT_ASSERT(!pTransferable->GetShell());
2239 CPPUNIT_ASSERT(!pTransferable2->GetShell());
2242 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf58604)
2244 #ifdef _WIN32
2245 // Allow linebreak character follows hanging punctuation immediately instead of
2246 // breaking at the start of the next line.
2247 createSwDoc("tdf58604.odt");
2248 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2249 CPPUNIT_ASSERT_EQUAL(
2250 OUString("PortionType::Break"),
2251 getXPath(pXmlDoc, "(/root/page/body/txt/SwParaPortion/SwLineLayout[1]/child::*)[last()]",
2252 "type"));
2253 #endif
2256 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf112025)
2258 mergeDocs("fdo112025.odt", "fdo112025-insert.docx");
2260 CPPUNIT_ASSERT_EQUAL(3, getParagraphs());
2262 uno::Reference<beans::XPropertySet> xStyle(
2263 getStyles(u"PageStyles"_ustr)->getByName(u"Standard"_ustr), uno::UNO_QUERY);
2264 CPPUNIT_ASSERT_EQUAL(true, getProperty<bool>(xStyle, u"IsLandscape"_ustr));
2267 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf72942)
2269 mergeDocs("fdo72942.docx", "fdo72942-insert.docx");
2271 // check styles of paragraphs added from [fdo72942.docx]
2272 const uno::Reference<text::XTextRange> xRun1 = getRun(getParagraph(1), 1);
2273 CPPUNIT_ASSERT_EQUAL(u"Default English (Liberation serif) text with "_ustr, xRun1->getString());
2274 CPPUNIT_ASSERT_EQUAL(u"Liberation Serif"_ustr,
2275 getProperty<OUString>(xRun1, u"CharFontName"_ustr));
2277 const uno::Reference<text::XTextRange> xRun2 = getRun(getParagraph(2), 1);
2278 CPPUNIT_ASSERT_EQUAL(u"Header 1 English text (Liberation sans) with "_ustr, xRun2->getString());
2279 CPPUNIT_ASSERT_EQUAL(u"Liberation Sans"_ustr,
2280 getProperty<OUString>(xRun2, u"CharFontName"_ustr));
2282 // check styles of paragraphs added from [fdo72942-insert.docx]
2283 const uno::Reference<text::XTextRange> xRun3 = getRun(getParagraph(4), 1);
2284 CPPUNIT_ASSERT_EQUAL(u"Default German text (Calibri) with "_ustr, xRun3->getString());
2285 CPPUNIT_ASSERT_EQUAL(u"Liberation Serif"_ustr,
2286 getProperty<OUString>(xRun3, u"CharFontName"_ustr));
2288 const uno::Reference<text::XTextRange> xRun4 = getRun(getParagraph(5), 1);
2289 CPPUNIT_ASSERT_EQUAL(u"Header 1 German text (Calibri Light) with "_ustr, xRun4->getString());
2290 CPPUNIT_ASSERT_EQUAL(u"Liberation Sans"_ustr,
2291 getProperty<OUString>(xRun4, u"CharFontName"_ustr));
2294 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf114306)
2296 createSwDoc("fdo114306.odt");
2297 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
2299 // There are 2 long paragraphs in cell A1.
2300 // A part of paragraph 2 should flow over to the second page but
2301 // *not* the whole paragraph. There should be 2 paragraphs on
2302 // page 1 and 1 paragraph on page 2.
2303 assertXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[1]/cell[1]/txt", 2);
2304 assertXPath(pXmlDoc, "/root/page[2]/body/tab[1]/row[1]/cell[1]/txt", 1);
2307 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf114306_2)
2309 // tdf#114306 fix unexpected page break in row-spanned table
2310 // load regression document without writer crash
2311 createSwDoc("fdo114306_2.odt");
2313 // correct number of pages
2314 CPPUNIT_ASSERT_EQUAL(4, getPages());
2317 // During insert of the document with list inside into the main document inside the list
2318 // we should merge both lists into one, when they have the same list properties
2319 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf113877)
2321 mergeDocs("tdf113877_insert_numbered_list.odt", "tdf113877_insert_numbered_list.odt");
2323 const OUString listId1 = getProperty<OUString>(getParagraph(1), u"ListId"_ustr);
2324 const OUString listId4 = getProperty<OUString>(getParagraph(4), u"ListId"_ustr);
2325 const OUString listId5 = getProperty<OUString>(getParagraph(5), u"ListId"_ustr);
2326 const OUString listId6 = getProperty<OUString>(getParagraph(6), u"ListId"_ustr);
2327 const OUString listId7 = getProperty<OUString>(getParagraph(7), u"ListId"_ustr);
2329 // the initial list with 4 list items
2330 CPPUNIT_ASSERT_EQUAL(listId1, listId4);
2332 // the last of the first list, and the first of the inserted list
2333 CPPUNIT_ASSERT_EQUAL(listId4, listId5);
2334 CPPUNIT_ASSERT_EQUAL(listId5, listId6);
2335 CPPUNIT_ASSERT_EQUAL(listId6, listId7);
2338 // The same test as testTdf113877() but merging of two list should not be performed.
2339 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf113877NoMerge)
2341 mergeDocs("tdf113877_insert_numbered_list.odt", "tdf113877_insert_numbered_list_abcd.odt");
2343 const OUString listId1 = getProperty<OUString>(getParagraph(1), u"ListId"_ustr);
2344 const OUString listId4 = getProperty<OUString>(getParagraph(4), u"ListId"_ustr);
2345 const OUString listId5 = getProperty<OUString>(getParagraph(5), u"ListId"_ustr);
2346 const OUString listId6 = getProperty<OUString>(getParagraph(6), u"ListId"_ustr);
2347 const OUString listId7 = getProperty<OUString>(getParagraph(7), u"ListId"_ustr);
2349 // the initial list with 4 list items
2350 CPPUNIT_ASSERT_EQUAL(listId1, listId4);
2352 // the last of the first list, and the first of the inserted list
2353 CPPUNIT_ASSERT(listId4 != listId5);
2354 CPPUNIT_ASSERT_EQUAL(listId5, listId6);
2355 CPPUNIT_ASSERT(listId6 != listId7);
2358 // Related test to testTdf113877(): Inserting into empty document a new document with list.
2359 // Insert position has NO its own paragraph style ("Standard" will be used).
2361 // Resulting document should be the same for following tests:
2362 // - testTdf113877_default_style()
2363 // - testTdf113877_Standard_style()
2365 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf113877_default_style)
2367 mergeDocs(nullptr, "tdf113877_insert_numbered_list_abcd.odt");
2369 const OUString listId1 = getProperty<OUString>(getParagraph(1), u"ListId"_ustr);
2370 const OUString listId2 = getProperty<OUString>(getParagraph(2), u"ListId"_ustr);
2371 const OUString listId3 = getProperty<OUString>(getParagraph(3), u"ListId"_ustr);
2373 CPPUNIT_ASSERT_EQUAL(listId1, listId2);
2374 CPPUNIT_ASSERT_EQUAL(listId1, listId3);
2377 // Related test to testTdf113877(): Inserting into empty document a new document with list.
2378 // Insert position has its own paragraph style derived from "Standard", but this style is the same as "Standard".
2380 // Resulting document should be the same for following tests:
2381 // - testTdf113877_default_style()
2382 // - testTdf113877_Standard_style()
2384 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf113877_Standard_style)
2386 mergeDocs("tdf113877_blank_ownStandard.odt", "tdf113877_insert_numbered_list_abcd.odt");
2388 const OUString listId1 = getProperty<OUString>(getParagraph(1), u"ListId"_ustr);
2389 const OUString listId2 = getProperty<OUString>(getParagraph(2), u"ListId"_ustr);
2390 const OUString listId3 = getProperty<OUString>(getParagraph(3), u"ListId"_ustr);
2392 CPPUNIT_ASSERT_EQUAL(listId1, listId2);
2393 CPPUNIT_ASSERT_EQUAL(listId1, listId3);
2396 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf113877_blank_bold_on)
2398 mergeDocs("tdf113877_blank_bold_on.odt", "tdf113877_insert_numbered_list_abcd.odt");
2400 const OUString listId1 = getProperty<OUString>(getParagraph(1), u"ListId"_ustr);
2401 const OUString listId2 = getProperty<OUString>(getParagraph(2), u"ListId"_ustr);
2402 const OUString listId3 = getProperty<OUString>(getParagraph(3), u"ListId"_ustr);
2404 CPPUNIT_ASSERT_EQUAL(listId1, listId2);
2405 CPPUNIT_ASSERT_EQUAL(listId1, listId3);
2408 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf107975)
2410 // This test also covers tdf#117185 tdf#110442
2412 createSwDoc("tdf107975.odt");
2414 uno::Reference<text::XTextGraphicObjectsSupplier> xTextGraphicObjectsSupplier(mxComponent,
2415 uno::UNO_QUERY);
2416 uno::Reference<container::XIndexAccess> xIndexAccess(
2417 xTextGraphicObjectsSupplier->getGraphicObjects(), uno::UNO_QUERY);
2419 uno::Reference<drawing::XShape> xShape(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
2421 CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER,
2422 getProperty<text::TextContentAnchorType>(xShape, u"AnchorType"_ustr));
2424 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
2426 dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
2428 dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
2430 //Position the mouse cursor (caret) after "ABC" below the blue image
2431 dispatchCommand(mxComponent, u".uno:GoRight"_ustr, {});
2432 dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
2434 // without the fix, it crashes
2435 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xIndexAccess->getCount());
2436 CPPUNIT_ASSERT_EQUAL(u"ABC"_ustr, getParagraph(1)->getString());
2437 dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
2438 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
2439 dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});
2440 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xIndexAccess->getCount());
2441 dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
2442 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
2443 dispatchCommand(mxComponent, u".uno:Redo"_ustr, {});
2444 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xIndexAccess->getCount());
2445 dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
2446 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
2448 //try again with anchor at start of doc which is another special case
2449 xShape.set(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
2450 uno::Reference<text::XTextContent> xShapeContent(xShape, uno::UNO_QUERY);
2451 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
2452 uno::Reference<text::XTextRange> const xStart = xTextDocument->getText()->getStart();
2453 xShapeContent->attach(xStart);
2455 CPPUNIT_ASSERT_EQUAL(text::TextContentAnchorType_AT_CHARACTER,
2456 getProperty<text::TextContentAnchorType>(xShape, u"AnchorType"_ustr));
2458 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
2460 dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
2462 dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
2464 //Position the mouse cursor (caret) after "ABC" below the blue image
2465 dispatchCommand(mxComponent, u".uno:GoRight"_ustr, {});
2466 dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
2468 // Fails quite a lot on multiple Jenkins slaves, but entirely reliably,
2469 // with:
2470 // sw/qa/extras/uiwriter/uiwriter4.cxx(2407) : error : Assertion
2471 // - Expected: 2
2472 // - Actual : 1
2473 // i.e. the xIndexAccess->getCount() line.
2474 #if 0
2475 // without the fix, it crashes
2476 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xIndexAccess->getCount());
2477 CPPUNIT_ASSERT_EQUAL(OUString("ABC"), getParagraph(1)->getString());
2478 dispatchCommand(mxComponent, ".uno:Undo", {});
2479 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
2480 dispatchCommand(mxComponent, ".uno:Redo", {});
2481 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xIndexAccess->getCount());
2482 dispatchCommand(mxComponent, ".uno:Undo", {});
2483 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
2484 dispatchCommand(mxComponent, ".uno:Redo", {});
2485 CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xIndexAccess->getCount());
2486 dispatchCommand(mxComponent, ".uno:Undo", {});
2487 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
2488 #endif
2491 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf113877_blank_bold_off)
2493 mergeDocs("tdf113877_blank_bold_off.odt", "tdf113877_insert_numbered_list_abcd.odt");
2495 const OUString listId1 = getProperty<OUString>(getParagraph(1), u"ListId"_ustr);
2496 const OUString listId2 = getProperty<OUString>(getParagraph(2), u"ListId"_ustr);
2497 const OUString listId3 = getProperty<OUString>(getParagraph(3), u"ListId"_ustr);
2499 CPPUNIT_ASSERT_EQUAL(listId1, listId2);
2500 CPPUNIT_ASSERT_EQUAL(listId1, listId3);
2503 // just care that this does crash/assert
2504 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testRhbz1810732) { mergeDocs(nullptr, "rhbz1810732.docx"); }
2506 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf142157)
2508 mergeDocs(nullptr, "tdf142157.odt");
2510 uno::Reference<text::XTextSectionsSupplier> xTextSectionsSupplier(mxComponent, uno::UNO_QUERY);
2511 uno::Reference<container::XIndexAccess> xSections(xTextSectionsSupplier->getTextSections(),
2512 uno::UNO_QUERY);
2514 // Without the fix in place, this test would have failed with
2515 // - Expected: 1
2516 // - Actual : 0
2517 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());
2520 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4, testTdf143320)
2522 createSwDoc("tdf143320.odt");
2523 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
2525 CPPUNIT_ASSERT_EQUAL(1, getPages());
2526 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("x"));
2528 dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
2530 dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});
2532 // Create a new document
2533 createSwDoc();
2534 pWrtShell = getSwDocShell()->GetWrtShell();
2535 CPPUNIT_ASSERT(pWrtShell);
2537 dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
2539 CPPUNIT_ASSERT_EQUAL(1, getPages());
2540 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("x"));
2542 dispatchCommand(mxComponent, u".uno:Undo"_ustr, {});
2544 CPPUNIT_ASSERT_EQUAL(1, getPages());
2545 CPPUNIT_ASSERT_EQUAL(u""_ustr, getParagraph(1)->getString());
2547 // Without the fix in place, this test would have crashed here
2548 dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
2550 CPPUNIT_ASSERT_EQUAL(1, getPages());
2551 CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("x"));
2554 CPPUNIT_PLUGIN_IMPLEMENT();
2556 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */