2 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
11 #include <com/sun/star/drawing/FillStyle.hpp>
12 #include <com/sun/star/style/CaseMap.hpp>
13 #include <swmodeltestbase.hxx>
16 #include <drawdoc.hxx>
17 #include <redline.hxx>
18 #include <dcontact.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>
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>
55 void lcl_selectCharacters(SwPaM
& rPaM
, sal_Int32 first
, sal_Int32 end
)
57 rPaM
.GetPoint()->nContent
.Assign(rPaM
.GetPointContentNode(), first
);
59 rPaM
.GetPoint()->nContent
.Assign(rPaM
.GetPointContentNode(), end
);
63 class SwUiWriterTest4
: public SwModelTestBase
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(),
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.
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(),
109 xParagraphAppend
->finishParagraph(uno::Sequence
<beans::PropertyValue
>());
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
)
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
);
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
);
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
);
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
);
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
);
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
);
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
;
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);
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);
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
;
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);
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 */
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
);
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 */
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
);
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
));
436 pWrtShell
= getSwDocShell()->GetWrtShell();
437 pWrtShell
->SttEndDoc(/*bStt=*/false);
438 pWrtShell
->Insert(u
" -1"_ustr
);
440 pWrtShell
->StartOfSection();
441 pCursor
= pWrtShell
->getShellCursor(false);
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 */
456 pWrtShell
= getSwDocShell()->GetWrtShell();
457 pWrtShell
->SttEndDoc(/*bStt=*/false);
458 pWrtShell
->Insert(u
" -1"_ustr
);
460 pWrtShell
->StartOfSection();
461 pCursor
= pWrtShell
->getShellCursor(false);
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.
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);
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(),
513 const uno::Reference
<text::XTextRange
> xInsertPos
= getRun(getParagraph(1), 1);
514 xParagraphAppend
->finishParagraphInsert(uno::Sequence
<beans::PropertyValue
>(), xInsertPos
);
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();
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
);
536 SwDoc
* pDoc
= getSwDoc();
538 // So we can clean up all references for reload
541 SwNodeIndex
aIdx(pDoc
->GetNodes().GetEndOfContent(), -1);
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());
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
);
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"/>
640 // <text:p text:style-name="Standard">
641 // <text:bookmark text:name="test"/>
645 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4
, testBookmarkCollapsed
)
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"
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"/>
678 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4
, testRemoveBookmarkText
)
682 // create a text document with "abcdef"
684 SwDoc
* pDoc
= getSwDoc();
687 SwNodeIndex
aIdx(pDoc
->GetNodes().GetEndOfContent(), -1);
689 pDoc
->getIDocumentContentOperations().InsertString(aPaM
, u
"abcdef"_ustr
);
692 // mark "abc" with "testBookmark" bookmark
694 SwNodeIndex
aIdx(pDoc
->GetNodes().GetEndOfContent(), -1);
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
);
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);
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());
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"
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).
744 // bookmark = ThisComponent.getBookmarks().getByName("test")
745 // bookmark.getAnchor().setString("abc")
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"/>
753 // <text:bookmark-end text:name="test"/>
757 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4
, testRemoveBookmarkTextAndAddNew
)
761 // create a text document with "abcdef"
763 SwDoc
* pDoc
= getSwDoc();
765 SwNodeIndex
aIdx(pDoc
->GetNodes().GetEndOfContent(), -1);
767 pDoc
->getIDocumentContentOperations().InsertString(aPaM
, u
"abcdef"_ustr
);
770 // mark "abc" with "testBookmark" bookmark
772 SwNodeIndex
aIdx(pDoc
->GetNodes().GetEndOfContent(), -1);
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
);
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);
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
,
805 // Create cursor from bookmark
806 uno::Reference
<text::XTextContent
> xTextContent(
807 xBookmarksSupplier
->getBookmarks()->getByName(u
"testBookmark"_ustr
),
809 uno::Reference
<text::XTextRange
> xRange
= xTextContent
->getAnchor();
810 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, xRange
->getString());
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());
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
);
840 // <text:p text:style-name="Standard">
841 // <text:bookmark-start text:name="test"/>
842 // <text:bookmark-end text:name="test"/>
849 // bookmark = ThisComponent.getBookmarks().getByName("test")
850 // bookmark.getAnchor().setString("abc")
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"/>
860 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4
, testRemoveBookmarkTextAndAddNewAfterReload
)
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());
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.
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
);
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");
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");
937 // This was 2: layout could not split the large outer table in the document
939 CPPUNIT_ASSERT_EQUAL(3, getPages());
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
)
954 SwDocShell
* pSourceShell
= getSwDocShell();
955 uno::Reference
<lang::XComponent
> xSourceComponent
= mxComponent
;
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.
987 SwDocShell
* pDocShell
= getSwDocShell();
988 SwWrtShell
* pWrtShell
= pDocShell
->GetWrtShell();
989 pWrtShell
->Insert(u
"text"_ustr
);
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");
1004 xmlDocUniquePtr pXmlDoc
= parseLayoutDump();
1005 assertXPath(pXmlDoc
, "/root/page/body/txt/anchored/SwAnchoredDrawObject[2]/SdrObject", "name",
1007 sal_Int32 nRectangle1
1008 = getXPath(pXmlDoc
, "/root/page/body/txt/anchored/SwAnchoredDrawObject[2]/bounds", "top")
1010 assertXPath(pXmlDoc
, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/SdrObject", "name",
1012 sal_Int32 nRectangle2
1013 = getXPath(pXmlDoc
, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/bounds", "top")
1015 CPPUNIT_ASSERT_GREATER(nRectangle1
, nRectangle2
);
1017 assertXPath(pXmlDoc
, "/root/page/body/txt/anchored/SwAnchoredDrawObject[3]/SdrObject", "name",
1019 sal_Int32 nRectangle3
1020 = getXPath(pXmlDoc
, "/root/page/body/txt/anchored/SwAnchoredDrawObject[3]/bounds", "top")
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");
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",
1039 sal_Int32 nRectangle2Top
1040 = getXPath(pXmlDoc
, "/root/page/body/txt/anchored/SwAnchoredDrawObject[1]/bounds", "top")
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());
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());
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());
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
)
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
1181 SwDoc
* pDoc
= getSwDoc();
1183 SwNodeIndex
aIdx(pDoc
->GetNodes().GetEndOfContent(), -1);
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.
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
)
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
1238 CPPUNIT_ASSERT_EQUAL(u
""_ustr
, getParagraph(1)->getString());
1241 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4
, testRedlineParam
)
1243 // Create a document with minimal content.
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.
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.
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
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.
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.
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.
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());
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();
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);
1593 = getXPath(pXmlDoc
, "//page[1]/body/tab/row/infos/bounds", "height").toInt32();
1595 = getXPath(pXmlDoc
, "//page[2]/body/tab/row/infos/bounds", "height").toInt32();
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
,
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();
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
,
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
)
1841 createSwDoc("tdf35021_tabOverMarginDemo.doc");
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
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
1858 = getXPath(pXmlDoc
, "//SwFixPortion[@type='PortionType::TabDecimal']", "width").toInt32();
1859 CPPUNIT_ASSERT_MESSAGE("Decimal Tab width is ~4096", nMargin
< nWidth
);
1863 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4
, testTdf106701_tabOverMarginAutotab
)
1865 createSwDoc("tdf106701_tabOverMarginAutotab.doc");
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();
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();
1917 = getXPath(pXmlDoc
, "(//SwParaPortion/SwLineLayout/child::*[@type='PortionType::Text'])[1]",
1921 = getXPath(pXmlDoc
, "(//SwParaPortion/SwLineLayout/child::*[@type='PortionType::Text'])[1]",
1925 = getXPath(pXmlDoc
, "(//SwParaPortion/SwLineLayout/child::*[@type='PortionType::Text'])[2]",
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
1947 if (!xHyphenator
->hasLocale(lang::Locale(u
"en"_ustr
, u
"US"_ustr
, OUString())))
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
);
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
);
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
);
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();
2036 "(//SwParaPortion/SwLineLayout/child::*[@type='PortionType::TabLeft'])[1]",
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
));
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",
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",
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",
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",
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",
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",
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",
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",
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",
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");
2114 CPPUNIT_ASSERT_EQUAL(false, pDoc
->getIDocumentSettingAccess().get(
2115 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS
));
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",
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",
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",
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",
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",
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",
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
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");
2197 CPPUNIT_ASSERT_EQUAL(true, pDoc
->getIDocumentSettingAccess().get(
2198 DocumentSettingId::MS_WORD_COMP_TRAILING_BLANKS
));
2201 CPPUNIT_TEST_FIXTURE(SwUiWriterTest4
, testCreateDocxAnnotation
)
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.
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
)
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()]",
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
,
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,
2470 // sw/qa/extras/uiwriter/uiwriter4.cxx(2407) : error : Assertion
2473 // i.e. the xIndexAccess->getCount() line.
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());
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(),
2514 // Without the fix in place, this test would have failed with
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
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: */