tdf#151423 Only allow modifiers for mouse scrollwheel events
[LibreOffice.git] / sw / qa / core / txtnode / txtnode.cxx
blob1882602c8d932e8327ac2c62272592141dea2523
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include <swmodeltestbase.hxx>
12 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
13 #include <comphelper/lok.hxx>
14 #include <comphelper/propertyvalue.hxx>
15 #include <com/sun/star/text/XTextTable.hpp>
16 #include <sfx2/viewsh.hxx>
17 #include <vcl/gdimtf.hxx>
18 #include <vcl/scheduler.hxx>
19 #include <sfx2/lokhelper.hxx>
20 #include <test/lokcallback.hxx>
21 #include <editeng/escapementitem.hxx>
23 #include <IDocumentStatistics.hxx>
24 #include <IDocumentLayoutAccess.hxx>
25 #include <fmtanchr.hxx>
26 #include <frameformats.hxx>
27 #include <wrtsh.hxx>
28 #include <unotxdoc.hxx>
29 #include <docsh.hxx>
30 #include <formatcontentcontrol.hxx>
31 #include <view.hxx>
32 #include <edtwin.hxx>
33 #include <txatbase.hxx>
34 #include <ndtxt.hxx>
35 #include <textcontentcontrol.hxx>
36 #include <swdtflvr.hxx>
37 #include <txtrfmrk.hxx>
38 #include <frmmgr.hxx>
39 #include <formatflysplit.hxx>
40 #include <ftnidx.hxx>
41 #include <rootfrm.hxx>
42 #include <pagefrm.hxx>
43 #include <txtfrm.hxx>
45 /// Covers sw/source/core/txtnode/ fixes.
46 class SwCoreTxtnodeTest : public SwModelTestBase
48 public:
49 SwCoreTxtnodeTest()
50 : SwModelTestBase(u"/sw/qa/core/txtnode/data/"_ustr)
55 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testBtlrCellChinese)
57 // Load a document with a table cell, with btlr cell direction. The cell has text which is
58 // classified as vertical, i.e. the glyph has the same direction in both the lrtb ("Latin") and
59 // tbrl ("Chinese") directions. Make sure that Chinese text is handled the same way in the btlr
60 // case as it's handled in the Latin case.
61 createSwDoc("btlr-cell-chinese.doc");
62 SwDocShell* pShell = getSwDocShell();
63 std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
64 MetafileXmlDump dumper;
65 xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
66 assertXPath(pXmlDoc, "//font[1]", "orientation", u"900");
67 // Without the accompanying fix in place, this test would have failed with:
68 // - Expected: false
69 // - Actual : true
70 // i.e. the glyph was rotated further, so it was upside down.
71 assertXPath(pXmlDoc, "//font[1]", "vertical", u"false");
74 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testSpecialInsertAfterMergedCells)
76 // Load a document with a table with bottom right cells merged vertically.
77 // SpecialInsert with alt-Enter must work here, too.
78 createSwDoc("special-insert-after-merged-cells.fodt");
79 SwDoc* pDoc = getSwDoc();
80 SwNodeOffset const nNodes(pDoc->GetNodes().Count());
81 SwDocShell* pShell = getSwDocShell();
82 SwWrtShell* pWrtShell = pShell->GetWrtShell();
83 // go to the merged cell
84 pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
86 // When pressing alt-Enter on the keyboard:
87 SwEditWin& rEditWin = pWrtShell->GetView().GetEditWin();
88 vcl::KeyCode aKeyCode(KEY_RETURN, KEY_MOD2);
89 KeyEvent aKeyEvent(' ', aKeyCode);
90 rEditWin.KeyInput(aKeyEvent);
92 // Without the accompanying fix in place, this test would have failed with:
93 // - Expected: nNodes + 1
94 // - Actual : nNodes
95 // i.e. new empty paragraph wasn't inserted under the table
96 CPPUNIT_ASSERT_EQUAL(nNodes + 1, pDoc->GetNodes().Count());
99 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTextBoxCopyAnchor)
101 createSwDoc("textbox-copy-anchor.docx");
102 SwDocShell* pShell = getSwDocShell();
103 SwWrtShell* pWrtShell = pShell->GetWrtShell();
104 SwDoc aClipboard;
105 pWrtShell->SelAll();
106 pWrtShell->Copy(aClipboard);
107 pWrtShell->SttEndDoc(/*bStart=*/false);
108 pWrtShell->Paste(aClipboard);
110 const auto& rFormats = *pShell->GetDoc()->GetSpzFrameFormats();
111 // Without the accompanying fix in place, this test would have failed with:
112 // - Expected: 4
113 // - Actual : 6
114 // i.e. 2 fly frames were copied twice.
115 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rFormats.size());
117 SwPosition aDrawAnchor1 = *rFormats[0]->GetAnchor().GetContentAnchor();
118 SwPosition aFlyAnchor1 = *rFormats[1]->GetAnchor().GetContentAnchor();
119 CPPUNIT_ASSERT_EQUAL(aFlyAnchor1.GetNodeIndex(), aDrawAnchor1.GetNodeIndex());
120 SwPosition aDrawAnchor2 = *rFormats[2]->GetAnchor().GetContentAnchor();
121 SwPosition aFlyAnchor2 = *rFormats[3]->GetAnchor().GetContentAnchor();
122 // This also failed, aFlyAnchor2 was wrong, as it got out of sync with aDrawAnchor2.
123 CPPUNIT_ASSERT_EQUAL(aFlyAnchor2.GetNodeIndex(), aDrawAnchor2.GetNodeIndex());
126 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTextBoxNodeSplit)
128 createSwDoc("textbox-node-split.docx");
129 SwDocShell* pShell = getSwDocShell();
130 SwWrtShell* pWrtShell = pShell->GetWrtShell();
131 pWrtShell->SttEndDoc(/*bStart=*/false);
132 // Without the accompanying fix in place, this would have crashed in
133 // SwFlyAtContentFrame::SwClientNotify().
134 pWrtShell->SplitNode();
137 namespace
139 struct ViewCallback
141 int m_nInvalidations = 0;
143 static void callback(int nType, const char* pPayload, void* pData);
144 void callbackImpl(int nType, const char* pPayload);
147 void ViewCallback::callback(int nType, const char* pPayload, void* pData)
149 static_cast<ViewCallback*>(pData)->callbackImpl(nType, pPayload);
152 void ViewCallback::callbackImpl(int nType, const char* /*pPayload*/)
154 switch (nType)
156 case LOK_CALLBACK_INVALIDATE_TILES:
158 ++m_nInvalidations;
160 break;
165 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTitleFieldInvalidate)
167 // Set up LOK to track invalidations.
168 comphelper::LibreOfficeKit::setActive(true);
170 // Given a document with a title field:
171 createSwDoc("title-field-invalidate.fodt");
172 getSwTextDoc()->initializeForTiledRendering({});
173 SwDocShell* pShell = getSwDocShell();
174 SwDoc* pDoc = pShell->GetDoc();
175 SwWrtShell* pWrtShell = pShell->GetWrtShell();
176 pWrtShell->SttEndDoc(/*bStt=*/false);
177 ViewCallback aCallback;
178 TestLokCallbackWrapper aCallbackWrapper(&ViewCallback::callback, &aCallback);
179 pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&aCallbackWrapper);
180 aCallbackWrapper.setLOKViewId(SfxLokHelper::getView(pWrtShell->GetSfxViewShell()));
181 Scheduler::ProcessEventsToIdle();
182 aCallback.m_nInvalidations = 0;
184 // When typing to the document:
185 pWrtShell->Insert(u"x"_ustr);
186 pWrtShell->GetSfxViewShell()->flushPendingLOKInvalidateTiles();
188 // Then make sure that only the text frame at the cursor is invalidated:
189 pDoc->getIDocumentStatistics().GetUpdatedDocStat(/*bCompleteAsync=*/true, /*bFields=*/false);
190 // Without the accompanying fix in place, this test would have failed with:
191 // - Expected: 1
192 // - Actual : 2
193 // i.e. the footer was also invalidated on each keypress.
194 CPPUNIT_ASSERT_EQUAL(1, aCallback.m_nInvalidations);
196 // Tear down LOK.
197 pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(nullptr);
198 mxComponent->dispose();
199 mxComponent.clear();
200 comphelper::LibreOfficeKit::setActive(false);
203 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testFlyAnchorUndo)
205 // Given a document with a fly frame, anchored after the last char of the document:
206 createSwDoc("fly-anchor-undo.odt");
207 SwDocShell* pShell = getSwDocShell();
208 SwDoc* pDoc = pShell->GetDoc();
209 const auto& rSpz = *pDoc->GetSpzFrameFormats();
210 sal_Int32 nExpected = rSpz[0]->GetAnchor().GetAnchorContentOffset();
212 // When deleting that last character and undoing it:
213 SwWrtShell* pWrtShell = pShell->GetWrtShell();
214 pWrtShell->SttEndDoc(/*bStt=*/false);
215 pWrtShell->DelLeft();
216 pWrtShell->Undo();
218 // Then make sure the anchor position after the undo is the same as the original:
219 sal_Int32 nActual = rSpz[0]->GetAnchor().GetAnchorContentOffset();
220 // Without the accompanying fix in place, this test would have failed with:
221 // - Expected: 3
222 // - Actual : 2
223 // i.e. the anchor position was left unchanged by the undo.
224 CPPUNIT_ASSERT_EQUAL(nExpected, nActual);
227 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testSplitNodeSuperscriptCopy)
229 // Given a document with superscript text at the end of a paragraph:
230 createSwDoc();
231 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
232 pWrtShell->Insert(u"1st"_ustr);
233 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 2, /*bBasicCall=*/false);
234 SfxItemSetFixed<RES_CHRATR_ESCAPEMENT, RES_CHRATR_ESCAPEMENT> aSet(pWrtShell->GetAttrPool());
235 SvxEscapementItem aItem(SvxEscapement::Superscript, RES_CHRATR_ESCAPEMENT);
236 aSet.Put(aItem);
237 pWrtShell->SetAttrSet(aSet);
239 // When hitting enter at the end of the paragraph:
240 pWrtShell->SttEndDoc(/*bStt=*/false);
241 pWrtShell->SplitNode(/*bAutoFormat=*/true);
243 // Then make sure that the superscript formatting doesn't appear on the next paragraph:
244 aSet.ClearItem(RES_CHRATR_ESCAPEMENT);
245 pWrtShell->GetCurAttr(aSet);
246 // Without the accompanying fix in place, this test would have failed, the unexpected
247 // superscript appeared in the next paragraph.
248 CPPUNIT_ASSERT(!aSet.HasItem(RES_CHRATR_ESCAPEMENT));
251 /* FIXME: behavior change reverted due to regression;
252 * see sw/source/core/txtnode/atrref.cxx
253 *CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testDontExpandRefmark)
255 * // Given a document with a refmark:
256 * createSwDoc();
258 * uno::Sequence<css::beans::PropertyValue> aArgs = {
259 * comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
260 * comphelper::makePropertyValue(
261 * "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} RNDpyJknp173F"))),
262 * comphelper::makePropertyValue("Content", uno::Any(OUString("foo"))),
263 * };
264 * dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
266 * SwDoc* pDoc = getSwDoc();
267 * SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
268 * SwPosition& rCursor = *pWrtShell->GetCursor()->GetPoint();
269 * SwTextNode* pTextNode = rCursor.GetNode().GetTextNode();
270 * std::vector<SwTextAttr*> aAttrs
271 * = pTextNode->GetTextAttrsAt(rCursor.GetContentIndex(), RES_TXTATR_REFMARK);
273 * auto& rRefmark = const_cast<SwFormatRefMark&>(aAttrs[0]->GetRefMark());
274 * auto pTextRefMark = const_cast<SwTextRefMark*>(rRefmark.GetTextRefMark());
276 * // When typing after the refmark...
277 * pWrtShell->SttEndDoc(true);
278 * pWrtShell->Right(SwCursorSkipMode::Chars, false, 3, false);
279 * pWrtShell->Insert(" bar");
281 * // and skipping back to insert a comma after the refmark
282 * pWrtShell->Left(SwCursorSkipMode::Chars, false, 4, false);
283 * pWrtShell->Insert(",");
285 * // Without the accompanying fix in place, this test would have failed with:
286 * // - Expected: 3
287 * // - Actual : 4
288 * // i.e. the reference mark expanded
289 * CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(*pTextRefMark->End()));
293 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testInsertDropDownContentControlTwice)
295 // Given an already selected dropdown content control:
296 createSwDoc();
297 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
298 pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);
300 // When trying to insert an inner one, make sure that we don't crash:
301 pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);
304 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testCheckboxContentControlKeyboard)
306 // Given an already selected checkbox content control:
307 createSwDoc();
308 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
309 pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX);
310 SwEditWin& rEditWin = pWrtShell->GetView().GetEditWin();
312 // When pressing space on the keyboard:
313 KeyEvent aKeyEvent(' ', KEY_SPACE);
314 rEditWin.KeyInput(aKeyEvent);
316 // Then make sure the state is toggled:
317 SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
318 SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
319 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
320 auto& rFormatContentControl
321 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
322 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
323 // Without the accompanying fix in place, this test would have failed, because the state
324 // remained unchanged.
325 CPPUNIT_ASSERT(pContentControl->GetChecked());
328 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testDropdownContentControlKeyboard)
330 // Given an already selected dropdown content control:
331 createSwDoc();
332 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
333 pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);
335 // When checking if alt-down should open a popup:
336 SwTextContentControl* pTextContentControl = pWrtShell->CursorInsideContentControl();
337 auto& rFormatContentControl
338 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
339 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
340 vcl::KeyCode aKeyCode(KEY_DOWN, KEY_MOD2);
341 bool bShouldOpen = pContentControl->ShouldOpenPopup(aKeyCode);
343 // Then make sure that the answer is yes for dropdowns:
344 // Without the accompanying fix in place, this test would have failed, the dropdown popup was
345 // mouse-only.
346 CPPUNIT_ASSERT(bShouldOpen);
349 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testPictureContentControlKeyboard)
351 // Given an already selected picture content control:
352 createSwDoc();
353 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
354 pWrtShell->InsertContentControl(SwContentControlType::PICTURE);
355 pWrtShell->GotoObj(/*bNext=*/true, GotoObjFlags::Any);
357 // When checking if enter should trigger the file picker:
358 const SwFrameFormat* pFlyFormat = pWrtShell->GetFlyFrameFormat();
359 const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
360 SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode();
361 SwTextNode* pTextNode = pAnchorNode->GetTextNode();
362 SwTextAttr* pAttr
363 = pTextNode->GetTextAttrAt(rFormatAnchor.GetAnchorContentOffset(),
364 RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent);
365 auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
366 auto& rFormatContentControl
367 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
368 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
369 bool bIsInteracting = pContentControl->IsInteractingCharacter('\r');
371 // Then make sure that the answer is yes for pictures:
372 // Without the accompanying fix in place, this test would have failed, the picture replacement
373 // file-picker was mouse-only.
374 CPPUNIT_ASSERT(bIsInteracting);
377 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testDateContentControlKeyboard)
379 // Given an already selected date content control:
380 createSwDoc();
381 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
382 pWrtShell->InsertContentControl(SwContentControlType::DATE);
384 // When checking if alt-down should open a popup:
385 SwTextContentControl* pTextContentControl = pWrtShell->CursorInsideContentControl();
386 auto& rFormatContentControl
387 = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
388 std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
389 vcl::KeyCode aKeyCode(KEY_DOWN, KEY_MOD2);
390 bool bShouldOpen = pContentControl->ShouldOpenPopup(aKeyCode);
392 // Then make sure that the answer is yes for date:
393 // Without the accompanying fix in place, this test would have failed, the date popup was
394 // mouse-only.
395 CPPUNIT_ASSERT(bShouldOpen);
398 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testContentControlCopy)
400 // Given a document with a content control:
401 createSwDoc();
402 SwDoc* pDoc = getSwDoc();
403 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
404 pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX);
406 // When copying that content control:
407 pWrtShell->SelAll();
408 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
409 xTransfer->Copy();
410 // Kill the selection, go to the end of the document:
411 pWrtShell->EndOfSection();
412 TransferableDataHelper aHelper(xTransfer);
413 SwTransferable::Paste(*pWrtShell, aHelper);
415 // Then make sure that the copy is also a checkbox:
416 SwContentControlManager& rManager = pDoc->GetContentControlManager();
417 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rManager.GetCount());
418 const SwFormatContentControl& rFormat1 = rManager.Get(0)->GetContentControl();
419 CPPUNIT_ASSERT_EQUAL(SwContentControlType::CHECKBOX, rFormat1.GetContentControl()->GetType());
420 const SwFormatContentControl& rFormat2 = rManager.Get(1)->GetContentControl();
421 // Without the accompanying fix in place, this test would have failed with:
422 // - Expected: 1 (CHECKBOX)
423 // - Actual : 0 (RICH_TEXT)
424 // i.e. properties were not copied from the source to the destination content control.
425 CPPUNIT_ASSERT_EQUAL(SwContentControlType::CHECKBOX, rFormat2.GetContentControl()->GetType());
428 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTdf157287)
430 createSwDoc("tdf157287.odt");
431 uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
432 auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
433 uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
434 uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);
436 CPPUNIT_ASSERT_EQUAL(u"30"_ustr, xField->getPresentation(false));
438 uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
439 uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
440 uno::UNO_QUERY);
441 uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
443 uno::Reference<text::XTextRange> xCellA1(xTextTable->getCellByName(u"B1"_ustr), uno::UNO_QUERY);
444 xCellA1->setString(u"100"_ustr);
446 dispatchCommand(mxComponent, u".uno:UpdateFields"_ustr, {});
448 // Without the fix in place, this test would have failed with
449 // - Expected: 120
450 // - Actual :
451 CPPUNIT_ASSERT_EQUAL(u"120"_ustr, xField->getPresentation(false));
454 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testFlySplitFootnote)
456 // Given a document with a split fly (to host a table):
457 createSwDoc();
458 SwDoc* pDoc = getSwDoc();
459 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
460 SwFlyFrameAttrMgr aMgr(true, pWrtShell, Frmmgr_Type::TEXT, nullptr);
461 RndStdIds eAnchor = RndStdIds::FLY_AT_PARA;
462 pWrtShell->StartAllAction();
463 aMgr.InsertFlyFrame(eAnchor, aMgr.GetPos(), aMgr.GetSize());
464 pWrtShell->EndAllAction();
465 pWrtShell->StartAllAction();
466 sw::FrameFormats<sw::SpzFrameFormat*>& rFlys = *pDoc->GetSpzFrameFormats();
467 sw::SpzFrameFormat* pFly = rFlys[0];
468 SwAttrSet aSet(pFly->GetAttrSet());
469 aSet.Put(SwFormatFlySplit(true));
470 pDoc->SetAttr(aSet, *pFly);
471 pWrtShell->EndAllAction();
472 pWrtShell->UnSelectFrame();
473 pWrtShell->LeaveSelFrameMode();
474 pWrtShell->GetView().AttrChangedNotify(nullptr);
475 pWrtShell->MoveSection(GoCurrSection, fnSectionEnd);
477 // When inserting a footnote:
478 pWrtShell->InsertFootnote(OUString());
480 // Then make sure the footnote gets inserted to the doc model.
481 // Without the accompanying fix in place, this test would have failed, insert code refused to
482 // have footnotes in all fly frames.
483 CPPUNIT_ASSERT(!pDoc->GetFootnoteIdxs().empty());
486 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testSplitFlyAnchorSplit)
488 // Given a document with a 2 pages long floating table:
489 createSwDoc("floattable-anchor-split.docx");
491 // When splitting the "AB" anchor text into "A" (remains as anchor text) and "B" (new text node
492 // after it):
493 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
494 pWrtShell->SttEndDoc(/*bStt=*/false);
495 pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
496 // Without the accompanying fix in place, this test would have failed with a layout loop.
497 pWrtShell->SplitNode();
499 // Then make sure the resulting layout is what we want:
500 SwDoc* pDoc = getSwDoc();
501 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
502 auto pPage1 = pLayout->Lower()->DynCastPageFrame();
503 CPPUNIT_ASSERT(pPage1);
504 // Page 1 has the master fly:
505 CPPUNIT_ASSERT(pPage1->GetSortedObjs());
506 auto pPage2 = pPage1->GetNext()->DynCastPageFrame();
507 CPPUNIT_ASSERT(pPage2);
508 // Page 2 has the follow fly:
509 CPPUNIT_ASSERT(pPage2->GetSortedObjs());
510 // Anchor text is now just "A":
511 auto pText1 = pPage2->FindFirstBodyContent()->DynCastTextFrame();
512 CPPUNIT_ASSERT_EQUAL(u"A"_ustr, pText1->GetText());
513 // New text frame is just "B":
514 auto pText2 = pText1->GetNext()->DynCastTextFrame();
515 CPPUNIT_ASSERT_EQUAL(u"B"_ustr, pText2->GetText());
517 // Also test that the new follow anchor text frame still has a fly portion, otherwise the anchor
518 // text and the floating table would overlap:
519 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
520 OUString aPortionType = getXPath(
521 pXmlDoc, "//page[2]/body/txt[1]/SwParaPortion/SwLineLayout[1]/child::*[1]", "type");
522 // Without the accompanying fix in place, this test would have failed with:
523 // - Expected: PortionType::Fly
524 // - Actual : PortionType::Para
525 // i.e. the fly portion was missing, text overlapped.
526 CPPUNIT_ASSERT_EQUAL(u"PortionType::Fly"_ustr, aPortionType);
529 CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testPlainContentControlCopy)
531 // Given a document with a plain text content control, all text selected and copied to the
532 // clipboard:
533 createSwDoc("plain-content-control-copy.docx");
534 SwDocShell* pDocShell = getSwDocShell();
535 SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
536 pWrtShell->SelAll();
538 rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
539 xTransfer->Copy();
542 // When closing that document, then make sure we don't crash on shutdown:
543 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
544 uno::Reference<util::XCloseable> xFrame(xModel->getCurrentController()->getFrame(),
545 uno::UNO_QUERY);
546 // Without the accompanying fix in place, this resulted in an assertion failure, a char style
547 // still had clients by the time it was deleted.
548 xFrame->close(false);
549 mxComponent.clear();
552 CPPUNIT_PLUGIN_IMPLEMENT();
554 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */