1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <swmodeltestbase.hxx>
12 #include <com/sun/star/view/XSelectionSupplier.hpp>
14 #include <comphelper/classids.hxx>
15 #include <tools/globname.hxx>
16 #include <svtools/embedhlp.hxx>
17 #include <editeng/frmdiritem.hxx>
18 #include <vcl/errinf.hxx>
19 #include <vcl/event.hxx>
20 #include <editeng/langitem.hxx>
21 #include <vcl/scheduler.hxx>
22 #include <comphelper/propertyvalue.hxx>
25 #include <fmtanchr.hxx>
26 #include <frameformats.hxx>
31 #include <swdtflvr.hxx>
32 #include <unotxdoc.hxx>
33 #include <UndoManager.hxx>
34 #include <IDocumentRedlineAccess.hxx>
36 #include <formatflysplit.hxx>
37 #include <IDocumentLayoutAccess.hxx>
38 #include <rootfrm.hxx>
39 #include <pagefrm.hxx>
40 #include <sortedobjs.hxx>
42 /// Covers sw/source/core/doc/ fixes.
43 class SwCoreDocTest
: public SwModelTestBase
47 : SwModelTestBase("/sw/qa/core/doc/data/")
52 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testMathInsertAnchorType
)
54 // Given an empty document.
56 SwDoc
* pDoc
= getSwDoc();
58 // When inserting an a math object.
59 SwWrtShell
* pShell
= pDoc
->GetDocShell()->GetWrtShell();
60 SvGlobalName
aGlobalName(SO3_SM_CLASSID
);
61 pShell
->InsertObject(svt::EmbeddedObjectRef(), &aGlobalName
);
63 // Then the anchor type should be as-char.
64 sw::SpzFrameFormats
& rFormats
= *pDoc
->GetSpzFrameFormats();
65 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rFormats
.size());
66 const SwFrameFormat
& rFormat
= *rFormats
[0];
67 const SwFormatAnchor
& rAnchor
= rFormat
.GetAnchor();
68 // Without the accompanying fix in place, this test would have failed with:
71 // i.e. the anchor type was at-char, not as-char.
72 CPPUNIT_ASSERT_EQUAL(RndStdIds::FLY_AS_CHAR
, rAnchor
.GetAnchorId());
73 ErrorRegistry::Reset();
76 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testTextboxTextRotateAngle
)
78 // Check the writing direction of the only TextFrame in the document.
79 createSwDoc("textbox-textrotateangle.odt");
80 SwDoc
* pDoc
= getSwDoc();
81 sw::SpzFrameFormats
& rFrameFormats
= *pDoc
->GetSpzFrameFormats();
82 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rFrameFormats
.size());
83 CPPUNIT_ASSERT_EQUAL(o3tl::narrowing
<sal_uInt16
>(RES_DRAWFRMFMT
), rFrameFormats
[0]->Which());
84 CPPUNIT_ASSERT_EQUAL(o3tl::narrowing
<sal_uInt16
>(RES_FLYFRMFMT
), rFrameFormats
[1]->Which());
85 SvxFrameDirection eActual
= rFrameFormats
[1]->GetAttrSet().GetItem(RES_FRAMEDIR
)->GetValue();
87 // Without the accompanying fix in place, this test would have failed with:
88 // - Expected: 5 (btlr)
89 // - Actual : 0 (lrtb)
90 // i.e. the writing direction was in the ODT file, but it was lost on import in the textbox
92 CPPUNIT_ASSERT_EQUAL(SvxFrameDirection::Vertical_LR_BT
, eActual
);
93 ErrorRegistry::Reset();
96 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testNumDownIndent
)
98 createSwDoc("num-down-indent.docx");
99 SwDoc
* pDoc
= getSwDoc();
100 SwDocShell
* pDocShell
= pDoc
->GetDocShell();
101 SwWrtShell
* pWrtShell
= pDocShell
->GetWrtShell();
102 pWrtShell
->Down(/*bSelect=*/false);
103 SwEditWin
& rEditWin
= pDocShell
->GetView()->GetEditWin();
104 KeyEvent
aKeyEvent(0, KEY_TAB
);
105 rEditWin
.KeyInput(aKeyEvent
);
106 SwTextNode
* pTextNode
= pWrtShell
->GetCursor()->GetPointNode().GetTextNode();
108 // Without the accompanying fix in place, this test would have failed with:
111 // i.e. pressing <tab> at the start of the paragraph did not change the layout.
112 CPPUNIT_ASSERT_EQUAL(OUString("\tB"), pTextNode
->GetText());
113 ErrorRegistry::Reset();
116 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testLocaleIndependentTemplate
)
118 createSwDoc("locale-independent-template.odt");
119 SwDoc
* pDoc
= getSwDoc();
120 SwDocShell
* pDocShell
= pDoc
->GetDocShell();
121 SwWrtShell
* pWrtShell
= pDocShell
->GetWrtShell();
122 SfxItemSet
aSet(pWrtShell
->GetAttrPool(), svl::Items
<RES_CHRATR_LANGUAGE
, RES_CHRATR_LANGUAGE
>);
123 pWrtShell
->GetCurAttr(aSet
);
124 const SvxLanguageItem
* pItem
= aSet
.GetItem(RES_CHRATR_LANGUAGE
);
125 CPPUNIT_ASSERT(pItem
);
126 LanguageType eLang
= pItem
->GetValue();
128 // Without the accompanying fix in place, this test would have failed with:
129 // - Expected: 1033 (LANGUAGE_ENGLISH_US)
130 // - Actual : 1023 (LANGUAGE_DONTKNOW)
131 // i.e. the status bar and the format -> character dialog didn't fall back to the UI locale when
132 // an explicit language was not set for the document.
133 CPPUNIT_ASSERT_EQUAL(LANGUAGE_ENGLISH_US
, eLang
);
134 ErrorRegistry::Reset();
137 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testTextBoxZOrder
)
139 createSwDoc("textbox-zorder.docx");
140 SwDoc
* pDoc
= getSwDoc();
141 sw::SpzFrameFormats
& rFormats
= *pDoc
->GetSpzFrameFormats();
142 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), rFormats
.size());
143 const sw::SpzFrameFormat
* pEllipse
= rFormats
[2];
144 const SdrObject
* pEllipseShape
= pEllipse
->FindRealSdrObject();
145 // Make sure we test the right shape.
146 CPPUNIT_ASSERT_EQUAL(OUString("Shape3"), pEllipseShape
->GetName());
147 // Without the accompanying fix in place, this test would have failed with:
150 // i.e. the ellipse was under the frame of the shape-frame pair, not on top of it.
151 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32
>(2), pEllipseShape
->GetOrdNum());
154 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testTextBoxMakeFlyFrame
)
156 // Given a document with an as-char textbox (as-char draw format + at-char fly format):
157 createSwDoc("textbox-makeflyframe.docx");
158 SwDoc
* pDoc
= getSwDoc();
160 // When cutting the textbox and pasting it to a new document:
162 SwDocShell
* pDocShell
= pDoc
->GetDocShell();
163 SwWrtShell
* pWrtShell
= pDocShell
->GetWrtShell();
164 rtl::Reference
<SwTransferable
> pTransfer
= new SwTransferable(*pWrtShell
);
166 TransferableDataHelper
aHelper(pTransfer
);
167 uno::Reference
<lang::XComponent
> xDoc2
168 = loadFromDesktop("private:factory/swriter", "com.sun.star.text.TextDocument", {});
169 SwXTextDocument
* pTextDoc2
= dynamic_cast<SwXTextDocument
*>(xDoc2
.get());
170 SwDocShell
* pDocShell2
= pTextDoc2
->GetDocShell();
171 SwWrtShell
* pWrtShell2
= pDocShell2
->GetWrtShell();
172 SwTransferable::Paste(*pWrtShell2
, aHelper
);
174 // Then make sure its fly frame is created.
175 mxComponent
->dispose();
177 xmlDocUniquePtr pLayout
= parseLayoutDump();
178 // Without the accompanying fix in place, this test would have failed, because the first text
179 // frame in the body frame had an SwAnchoredDrawObject anchored to it, but not a fly frame, so
180 // a blank square was painted, not the image.
181 assertXPath(pLayout
, "/root/page/body/txt/anchored/fly", 1);
184 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testIMEGrouping
)
186 // TODO figure out why the ext text input in this test code reaches the wrong window on
188 #if !defined MACOSX && !defined _WIN32
189 // Given an empty document:
191 SwDoc
* pDoc
= getSwDoc();
192 // Make sure no idle is in action, so the ExtTextInput events go to SwEditWin.
193 Scheduler::ProcessEventsToIdle();
195 // When pressing two keys via IME:
196 SwDocShell
* pDocShell
= pDoc
->GetDocShell();
197 SwEditWin
& rEditWin
= pDocShell
->GetView()->GetEditWin();
198 rEditWin
.PostExtTextInputEvent(VclEventId::ExtTextInput
, "a");
199 rEditWin
.PostExtTextInputEvent(VclEventId::EndExtTextInput
, "");
200 rEditWin
.PostExtTextInputEvent(VclEventId::ExtTextInput
, "b");
201 rEditWin
.PostExtTextInputEvent(VclEventId::EndExtTextInput
, "");
203 // Then make sure that gets grouped together to a single undo action:
204 SwWrtShell
* pWrtShell
= pDocShell
->GetWrtShell();
205 SwTextNode
* pTextNode
= pWrtShell
->GetCursor()->GetPointNode().GetTextNode();
206 CPPUNIT_ASSERT_EQUAL(OUString("ab"), pTextNode
->GetText());
207 // Without the accompanying fix in place, this test would have failed with:
210 // i.e. 2 subsequent IME events got their own undo actions.
211 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pDoc
->GetUndoManager().GetUndoActionCount());
215 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testImageHyperlinkStyle
)
217 // Given a document with an image with a hyperlink:
219 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
220 uno::Reference
<text::XTextDocument
> xDocument(mxComponent
, uno::UNO_QUERY
);
221 uno::Reference
<text::XText
> xText
= xDocument
->getText();
222 uno::Reference
<text::XTextCursor
> xCursor
= xText
->createTextCursor();
223 uno::Reference
<text::XTextContent
> xImage(
224 xFactory
->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY
);
225 xText
->insertTextContent(xCursor
, xImage
, /*bAbsorb=*/false);
226 uno::Reference
<beans::XPropertySet
> xImageProps(xImage
, uno::UNO_QUERY
);
227 OUString aExpected
= "http://www.example.com";
228 xImageProps
->setPropertyValue("HyperLinkURL", uno::Any(aExpected
));
230 // When applying a frame style on it:
231 xImageProps
->setPropertyValue("FrameStyleName", uno::Any(OUString("Frame")));
233 // Then make sure that the hyperlink is not lost:
234 auto aActual
= getProperty
<OUString
>(xImageProps
, "HyperLinkURL");
235 // Without the accompanying fix in place, this test would have failed with:
236 // - Expected: http://www.example.com
238 // i.e. the link was lost, even if the frame style dialog doesn't allow specifying a link on
240 CPPUNIT_ASSERT_EQUAL(aExpected
, aActual
);
243 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testContentControlDelete
)
245 // Given a document with a content control:
247 SwDoc
* pDoc
= getSwDoc();
248 uno::Reference
<lang::XMultiServiceFactory
> xMSF(mxComponent
, uno::UNO_QUERY
);
249 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
250 uno::Reference
<text::XText
> xText
= xTextDocument
->getText();
251 uno::Reference
<text::XTextCursor
> xCursor
= xText
->createTextCursor();
252 xText
->insertString(xCursor
, "test", /*bAbsorb=*/false);
253 xCursor
->gotoStart(/*bExpand=*/false);
254 xCursor
->gotoEnd(/*bExpand=*/true);
255 uno::Reference
<text::XTextContent
> xContentControl(
256 xMSF
->createInstance("com.sun.star.text.ContentControl"), uno::UNO_QUERY
);
257 xText
->insertTextContent(xCursor
, xContentControl
, /*bAbsorb=*/true);
259 // When deleting the dummy character at the end of the content control:
260 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
261 pWrtShell
->SttEndDoc(/*bStt=*/false);
262 pWrtShell
->DelLeft();
264 // Then make sure that we only enter the content control, to be consistent with the start dummy
266 SwTextNode
* pTextNode
= pWrtShell
->GetCursor()->GetMark()->GetNode().GetTextNode();
267 // Without the accompanying fix in place, this test would have failed with:
268 // - Expected: ^Atest^A
270 // i.e. the end dummy character got deleted, but not the first one, which is inconsistent.
271 CPPUNIT_ASSERT_EQUAL(OUString("\x0001test\x0001"), pTextNode
->GetText());
274 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testCopyBookmarks
)
276 // Given a document with a bookmark in a header that is linked later:
277 createSwDoc("copy-bookmarks.docx");
278 SwDoc
* pDoc
= getSwDoc();
280 // When checking the # of non-copy bookmarks in the resulting doc model:
281 sal_Int32 nActual
= 0;
282 for (auto it
= pDoc
->getIDocumentMarkAccess()->getBookmarksBegin();
283 it
!= pDoc
->getIDocumentMarkAccess()->getBookmarksEnd(); ++it
)
285 if ((*it
)->GetName().indexOf("Copy") == -1)
291 // Then make sure we have a single non-copy bookmark, with no duplications:
292 // Without the accompanying fix in place, this test would have failed with:
295 // i.e. the 2nd header had a duplicated bookmark without "Copy" in its name.
296 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), nActual
);
298 // Also, when checking the # of non-copy images in the resulting doc model:
300 for (auto pSpz
: *pDoc
->GetSpzFrameFormats())
302 if (pSpz
->GetName().indexOf("Copy") == -1)
308 // Then make sure we have a single non-copy image, with no duplications:
309 // Without the accompanying fix in place, this test would have failed with:
312 // i.e. the 2nd header had a duplicated image without "Copy" in its name.
313 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), nActual
);
316 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testLinkedStyleDelete
)
318 // Given a document with linked styles: myparastyle is linked to mycharstyle and vica versa:
320 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
321 uno::Reference
<beans::XPropertySet
> xParaStyle(
322 xFactory
->createInstance("com.sun.star.style.ParagraphStyle"), uno::UNO_QUERY
);
323 uno::Reference
<beans::XPropertySet
> xCharStyle(
324 xFactory
->createInstance("com.sun.star.style.CharacterStyle"), uno::UNO_QUERY
);
325 uno::Reference
<container::XNameContainer
> xParaStyles(getStyles("ParagraphStyles"),
327 xParaStyles
->insertByName("myparastyle", uno::Any(xParaStyle
));
328 uno::Reference
<container::XNameContainer
> xCharStyles(getStyles("CharacterStyles"),
330 xCharStyles
->insertByName("mycharstyle", uno::Any(xCharStyle
));
331 xParaStyle
->setPropertyValue("LinkStyle", uno::Any(OUString("mycharstyle")));
332 xCharStyle
->setPropertyValue("LinkStyle", uno::Any(OUString("myparastyle")));
334 // When deleting the paragraph style (and only that):
335 xParaStyles
->removeByName("myparastyle");
337 // Then make sure we don't crash on save:
338 uno::Reference
<frame::XStorable
> xStorable(mxComponent
, uno::UNO_QUERY
);
339 uno::Sequence
<beans::PropertyValue
> aArgs
= {
340 comphelper::makePropertyValue("FilterName", OUString("writer8")),
342 xStorable
->storeAsURL(maTempFile
.GetURL(), aArgs
);
347 /// This selection listener calls getAnchor() on selection change, which creates UNO cursors and is
348 /// invoked in the middle of a bookmark deletion.
349 struct SelectionChangeListener
: public cppu::WeakImplHelper
<view::XSelectionChangeListener
>
351 uno::Reference
<container::XNameAccess
> m_xBookmarks
;
352 std::vector
<uno::Reference
<text::XTextRange
>> m_aAnchors
;
355 SelectionChangeListener(const uno::Reference
<container::XNameAccess
>& xBookmarks
);
356 // view::XSelectionChangeListener
357 void SAL_CALL
selectionChanged(const lang::EventObject
& rEvent
) override
;
359 // lang::XEventListener
360 void SAL_CALL
disposing(const lang::EventObject
& rSource
) override
;
364 SelectionChangeListener::SelectionChangeListener(
365 const uno::Reference
<container::XNameAccess
>& xBookmarks
)
366 : m_xBookmarks(xBookmarks
)
370 void SelectionChangeListener::selectionChanged(const lang::EventObject
& /*rEvent*/)
372 uno::Sequence
<OUString
> aElementNames
= m_xBookmarks
->getElementNames();
373 for (const auto& rName
: aElementNames
)
375 uno::Reference
<text::XTextContent
> xTextContent(m_xBookmarks
->getByName(rName
),
377 m_aAnchors
.push_back(xTextContent
->getAnchor());
381 void SelectionChangeListener::disposing(const lang::EventObject
& /*rSource*/) {}
383 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testBookmarkDeleteListeners
)
385 // Given a document with 2 bookmarks:
387 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
388 uno::Reference
<text::XText
> xText
= xTextDocument
->getText();
389 uno::Reference
<text::XTextCursor
> xCursor
= xText
->createTextCursor();
391 xText
->insertString(xCursor
, "test", /*bAbsorb=*/false);
392 xCursor
->gotoStart(/*bExpand=*/false);
393 xCursor
->gotoEnd(/*bExpand=*/true);
394 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
395 uno::Reference
<text::XTextContent
> xBookmark(
396 xFactory
->createInstance("com.sun.star.text.Bookmark"), uno::UNO_QUERY
);
397 uno::Reference
<container::XNamed
> xBookmarkNamed(xBookmark
, uno::UNO_QUERY
);
398 xBookmarkNamed
->setName("mybookmark");
399 xText
->insertTextContent(xCursor
, xBookmark
, /*bAbsorb=*/true);
402 xCursor
->gotoEnd(/*bExpand=*/false);
403 xText
->insertString(xCursor
, "test2", /*bAbsorb=*/false);
404 xCursor
->goLeft(4, /*bExpand=*/true);
405 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
406 uno::Reference
<text::XTextContent
> xBookmark(
407 xFactory
->createInstance("com.sun.star.text.Bookmark"), uno::UNO_QUERY
);
408 uno::Reference
<container::XNamed
> xBookmarkNamed(xBookmark
, uno::UNO_QUERY
);
409 xBookmarkNamed
->setName("mybookmark2");
410 xText
->insertTextContent(xCursor
, xBookmark
, /*bAbsorb=*/true);
412 uno::Reference
<text::XBookmarksSupplier
> xBookmarksSupplier(mxComponent
, uno::UNO_QUERY
);
413 uno::Reference
<container::XNameAccess
> xBookmarks
= xBookmarksSupplier
->getBookmarks();
415 // When registering a selection listener that creates uno marks:
416 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
417 uno::Reference
<view::XSelectionSupplier
> xController(xModel
->getCurrentController(),
419 xController
->addSelectionChangeListener(new SelectionChangeListener(xBookmarks
));
421 // Then make sure that deleting a bookmark doesn't crash:
422 uno::Reference
<lang::XComponent
> xBookmark(xBookmarks
->getByName("mybookmark2"),
424 // Without the accompanying fix in place, this test would have crashed, an invalidated iterator
425 // was used with erase().
426 xBookmark
->dispose();
429 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testBookmarkDeleteRedline
)
431 // Given a document with redlines, a mark (annotation mark) inside a redline:
432 createSwDoc("bookmark-delete-redline.doc");
433 SwDoc
* pDoc
= getSwDoc();
435 // When hiding deletions / showing only inserts, make sure we don't crash:
436 // Without the accompanying fix in place, this test would have crashed, equal_range() was used
437 // on an unsorted container.
438 pDoc
->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::ShowInsert
);
441 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testHeaderFooterDelete
)
443 // Given a document with bookmarks in header/footers:
444 // When importing that document:
445 // Then make sure that we don't crash:
446 // Without the accompanying fix in place, this test would have crashed, an invalidated iterator
447 // was used in sw::mark::MarkManager::deleteMarks().
448 createSwDoc("header-footer-delete.docx");
451 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testSplitFlyChain
)
453 // Given a document with 2 fly frames, first is allowed to split, second is not:
455 SwWrtShell
* pWrtShell
= getSwDocShell()->GetWrtShell();
456 SwFlyFrameAttrMgr
aMgr(true, pWrtShell
, Frmmgr_Type::TEXT
, nullptr);
457 RndStdIds eAnchor
= RndStdIds::FLY_AT_PARA
;
458 aMgr
.InsertFlyFrame(eAnchor
, aMgr
.GetPos(), aMgr
.GetSize());
459 SwDoc
* pDoc
= getSwDoc();
460 auto& rFlys
= *pDoc
->GetSpzFrameFormats();
462 pWrtShell
->StartAllAction();
463 auto pFly
= rFlys
[0];
464 SwAttrSet
aSet(pFly
->GetAttrSet());
465 aSet
.Put(SwFormatFlySplit(true));
466 pDoc
->SetAttr(aSet
, *pFly
);
467 pWrtShell
->EndAllAction();
469 pWrtShell
->UnSelectFrame();
470 pWrtShell
->SttEndDoc(/*bStart=*/false);
471 aMgr
.InsertFlyFrame(eAnchor
, aMgr
.GetPos(), aMgr
.GetSize());
472 auto pFly
= rFlys
[0];
473 auto pFly2
= rFlys
[1];
475 // When checking if chaining is allowed:
476 SwChainRet eActual
= pDoc
->Chainable(*pFly
, *pFly2
);
477 // Then make sure the source is rejected if it is a split fly:
478 // Without the accompanying fix in place, this test would have failed with:
479 // - Expected: 5 (SwChainRet::SOURCE_CHAINED)
480 // - Actual : 0 (SwChainRet::OK)
481 // i.e. the UI allowed chaining for floating tables, which doesn't make sense.
482 CPPUNIT_ASSERT_EQUAL(SwChainRet::SOURCE_CHAINED
, eActual
);
484 // Also test the other way around, that should not be OK, either.
485 eActual
= pDoc
->Chainable(*pFly2
, *pFly
);
486 CPPUNIT_ASSERT_EQUAL(SwChainRet::IS_IN_CHAIN
, eActual
);
489 CPPUNIT_TEST_FIXTURE(SwCoreDocTest
, testSplitExpandGlossary
)
491 // Given a document with a split fly (2 pages) and a 'dt' at the end:
492 createSwDoc("floating-table-dummy-text.docx");
493 SwWrtShell
* pWrtShell
= getSwDocShell()->GetWrtShell();
494 pWrtShell
->SttEndDoc(/*bStt=*/false);
496 // When expanding 'dt' to an actual dummy text:
497 dispatchCommand(mxComponent
, ".uno:ExpandGlossary", {});
499 // Then make sure the 2 fly frames stay on the 2 pages:
500 SwDoc
* pDoc
= getSwDoc();
501 SwRootFrame
* pLayout
= pDoc
->getIDocumentLayoutAccess().GetCurrentLayout();
502 auto pPage1
= dynamic_cast<SwPageFrame
*>(pLayout
->Lower());
503 CPPUNIT_ASSERT(pPage1
);
504 CPPUNIT_ASSERT(pPage1
->GetSortedObjs());
505 const SwSortedObjs
& rPage1Objs
= *pPage1
->GetSortedObjs();
506 // Without the accompanying fix in place, this test would have failed with:
509 // i.e. both parts of the split fly chain were on page 1.
510 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage1Objs
.size());
511 auto pPage2
= dynamic_cast<SwPageFrame
*>(pPage1
->GetNext());
512 CPPUNIT_ASSERT(pPage2
);
513 CPPUNIT_ASSERT(pPage2
->GetSortedObjs());
514 const SwSortedObjs
& rPage2Objs
= *pPage2
->GetSortedObjs();
515 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage2Objs
.size());
518 CPPUNIT_PLUGIN_IMPLEMENT();
520 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */