Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/sw/qa/core/txtnode/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 26 kB image not shown  

Quelle  txtnode.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */


#include <swmodeltestbase.hxx>

#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <comphelper/lok.hxx>
#include <comphelper/propertyvalue.hxx>
#include <com/sun/star/text/XTextTable.hpp>
#include <sfx2/viewsh.hxx>
#include <vcl/gdimtf.hxx>
#include <vcl/scheduler.hxx>
#include <sfx2/lokhelper.hxx>
#include <test/lokcallback.hxx>
#include <editeng/escapementitem.hxx>

#include <IDocumentStatistics.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <fmtanchr.hxx>
#include <frameformats.hxx>
#include <wrtsh.hxx>
#include <unotxdoc.hxx>
#include <docsh.hxx>
#include <formatcontentcontrol.hxx>
#include <view.hxx>
#include <edtwin.hxx>
#include <txatbase.hxx>
#include <ndtxt.hxx>
#include <textcontentcontrol.hxx>
#include <swdtflvr.hxx>
#include <txtrfmrk.hxx>
#include <frmmgr.hxx>
#include <formatflysplit.hxx>
#include <ftnidx.hxx>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <txtfrm.hxx>
#include <PostItMgr.hxx>
#include <AnnotationWin.hxx>
#include <docufld.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <MarkManager.hxx>

/// Covers sw/source/core/txtnode/ fixes.
class SwCoreTxtnodeTest : public SwModelTestBase
{
public:
    SwCoreTxtnodeTest()
        : SwModelTestBase(u"/sw/qa/core/txtnode/data/"_ustr)
    {
    }
};

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testBtlrCellChinese)
{
    // Load a document with a table cell, with btlr cell direction.  The cell has text which is
    // classified as vertical, i.e. the glyph has the same direction in both the lrtb ("Latin") and
    // tbrl ("Chinese") directions. Make sure that Chinese text is handled the same way in the btlr
    // case as it's handled in the Latin case.
    createSwDoc("btlr-cell-chinese.doc");
    SwDocShell* pShell = getSwDocShell();
    std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile();
    MetafileXmlDump dumper;
    xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile);
    assertXPath(pXmlDoc, "//font[1]", "orientation", u"900");
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: false
    // - Actual  : true
    // i.e. the glyph was rotated further, so it was upside down.
    assertXPath(pXmlDoc, "//font[1]", "vertical", u"false");
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testSpecialInsertAfterMergedCells)
{
    // Load a document with a table with bottom right cells merged vertically.
    // SpecialInsert with alt-Enter must work here, too.
    createSwDoc("special-insert-after-merged-cells.fodt");
    SwDoc* pDoc = getSwDoc();
    SwNodeOffset const nNodes(pDoc->GetNodes().Count());
    SwDocShell* pShell = getSwDocShell();
    SwWrtShell* pWrtShell = pShell->GetWrtShell();
    // go to the merged cell
    pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);

    // When pressing alt-Enter on the keyboard:
    SwEditWin& rEditWin = pWrtShell->GetView().GetEditWin();
    vcl::KeyCode aKeyCode(KEY_RETURN, KEY_MOD2);
    KeyEvent aKeyEvent(' ', aKeyCode);
    rEditWin.KeyInput(aKeyEvent);

    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: nNodes + 1
    // - Actual  : nNodes
    // i.e. new empty paragraph wasn't inserted under the table
    CPPUNIT_ASSERT_EQUAL(nNodes + 1, pDoc->GetNodes().Count());
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTextBoxCopyAnchor)
{
    createSwDoc("textbox-copy-anchor.docx");
    SwDocShell* pShell = getSwDocShell();
    SwWrtShell* pWrtShell = pShell->GetWrtShell();
    SwDoc aClipboard;
    pWrtShell->SelAll();
    pWrtShell->Copy(aClipboard);
    pWrtShell->SttEndDoc(/*bStart=*/false);
    pWrtShell->Paste(aClipboard);

    const auto& rFormats = *pShell->GetDoc()->GetSpzFrameFormats();
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: 4
    // - Actual  : 6
    // i.e. 2 fly frames were copied twice.
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), rFormats.size());

    SwPosition aDrawAnchor1 = *rFormats[0]->GetAnchor().GetContentAnchor();
    SwPosition aFlyAnchor1 = *rFormats[1]->GetAnchor().GetContentAnchor();
    CPPUNIT_ASSERT_EQUAL(aFlyAnchor1.GetNodeIndex(), aDrawAnchor1.GetNodeIndex());
    SwPosition aDrawAnchor2 = *rFormats[2]->GetAnchor().GetContentAnchor();
    SwPosition aFlyAnchor2 = *rFormats[3]->GetAnchor().GetContentAnchor();
    // This also failed, aFlyAnchor2 was wrong, as it got out of sync with aDrawAnchor2.
    CPPUNIT_ASSERT_EQUAL(aFlyAnchor2.GetNodeIndex(), aDrawAnchor2.GetNodeIndex());
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTextBoxNodeSplit)
{
    createSwDoc("textbox-node-split.docx");
    SwDocShell* pShell = getSwDocShell();
    SwWrtShell* pWrtShell = pShell->GetWrtShell();
    pWrtShell->SttEndDoc(/*bStart=*/false);
    // Without the accompanying fix in place, this would have crashed in
    // SwFlyAtContentFrame::SwClientNotify().
    pWrtShell->SplitNode();
}

namespace
{
struct ViewCallback
{
    int m_nInvalidations = 0;

    static void callback(int nType, const char* pPayload, void* pData);
    void callbackImpl(int nType, const char* pPayload);
};

void ViewCallback::callback(int nType, const char* pPayload, void* pData)
{
    static_cast<ViewCallback*>(pData)->callbackImpl(nType, pPayload);
}

void ViewCallback::callbackImpl(int nType, const char/*pPayload*/)
{
    switch (nType)
    {
        case LOK_CALLBACK_INVALIDATE_TILES:
        {
            ++m_nInvalidations;
        }
        break;
    }
}
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTitleFieldInvalidate)
{
    // Set up LOK to track invalidations.
    comphelper::LibreOfficeKit::setActive(true);

    // Given a document with a title field:
    createSwDoc("title-field-invalidate.fodt");
    getSwTextDoc()->initializeForTiledRendering({});
    SwDocShell* pShell = getSwDocShell();
    SwDoc* pDoc = pShell->GetDoc();
    SwWrtShell* pWrtShell = pShell->GetWrtShell();
    pWrtShell->SttEndDoc(/*bStt=*/false);
    ViewCallback aCallback;
    TestLokCallbackWrapper aCallbackWrapper(&ViewCallback::callback, &aCallback);
    pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(&aCallbackWrapper);
    aCallbackWrapper.setLOKViewId(SfxLokHelper::getView(pWrtShell->GetSfxViewShell()));
    Scheduler::ProcessEventsToIdle();
    aCallback.m_nInvalidations = 0;

    // When typing to the document:
    pWrtShell->Insert(u"x"_ustr);
    pWrtShell->GetSfxViewShell()->flushPendingLOKInvalidateTiles();

    // Then make sure that only the text frame at the cursor is invalidated:
    pDoc->getIDocumentStatistics().GetUpdatedDocStat(/*bCompleteAsync=*/true, /*bFields=*/false);
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: 1
    // - Actual  : 2
    // i.e. the footer was also invalidated on each keypress.
    CPPUNIT_ASSERT_EQUAL(1, aCallback.m_nInvalidations);

    // Tear down LOK.
    pWrtShell->GetSfxViewShell()->setLibreOfficeKitViewCallback(nullptr);
    mxComponent->dispose();
    mxComponent.clear();
    comphelper::LibreOfficeKit::setActive(false);
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testFlyAnchorUndo)
{
    // Given a document with a fly frame, anchored after the last char of the document:
    createSwDoc("fly-anchor-undo.odt");
    SwDocShell* pShell = getSwDocShell();
    SwDoc* pDoc = pShell->GetDoc();
    const auto& rSpz = *pDoc->GetSpzFrameFormats();
    sal_Int32 nExpected = rSpz[0]->GetAnchor().GetAnchorContentOffset();

    // When deleting that last character and undoing it:
    SwWrtShell* pWrtShell = pShell->GetWrtShell();
    pWrtShell->SttEndDoc(/*bStt=*/false);
    pWrtShell->DelLeft();
    pWrtShell->Undo();

    // Then make sure the anchor position after the undo is the same as the original:
    sal_Int32 nActual = rSpz[0]->GetAnchor().GetAnchorContentOffset();
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: 3
    // - Actual  : 2
    // i.e. the anchor position was left unchanged by the undo.
    CPPUNIT_ASSERT_EQUAL(nExpected, nActual);
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testSplitNodeSuperscriptCopy)
{
    // Given a document with superscript text at the end of a paragraph:
    createSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->Insert(u"1st"_ustr);
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 2, /*bBasicCall=*/false);
    SfxItemSet aSet(SfxItemSet::makeFixedSfxItemSet<RES_CHRATR_ESCAPEMENT, RES_CHRATR_ESCAPEMENT>(
        pWrtShell->GetAttrPool()));
    SvxEscapementItem aItem(SvxEscapement::Superscript, RES_CHRATR_ESCAPEMENT);
    aSet.Put(aItem);
    pWrtShell->SetAttrSet(aSet);

    // When hitting enter at the end of the paragraph:
    pWrtShell->SttEndDoc(/*bStt=*/false);
    pWrtShell->SplitNode(/*bAutoFormat=*/true);

    // Then make sure that the superscript formatting doesn't appear on the next paragraph:
    aSet.ClearItem(RES_CHRATR_ESCAPEMENT);
    pWrtShell->GetCurAttr(aSet);
    // Without the accompanying fix in place, this test would have failed, the unexpected
    // superscript appeared in the next paragraph.
    CPPUNIT_ASSERT(!aSet.HasItem(RES_CHRATR_ESCAPEMENT));
}

/* FIXME: behavior change reverted due to regression;
 * see sw/source/core/txtnode/atrref.cxx
 *CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testDontExpandRefmark)
 *{
 *    // Given a document with a refmark:
 *    createSwDoc();
 *
 *    uno::Sequence<css::beans::PropertyValue> aArgs = {
 *        comphelper::makePropertyValue("TypeName", uno::Any(OUString("SetRef"))),
 *        comphelper::makePropertyValue(
 *            "Name", uno::Any(OUString("ZOTERO_ITEM CSL_CITATION {} RNDpyJknp173F"))),
 *        comphelper::makePropertyValue("Content", uno::Any(OUString("foo"))),
 *    };
 *    dispatchCommand(mxComponent, ".uno:InsertField", aArgs);
 *
 *    SwDoc* pDoc = getSwDoc();
 *    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
 *    SwPosition& rCursor = *pWrtShell->GetCursor()->GetPoint();
 *    SwTextNode* pTextNode = rCursor.GetNode().GetTextNode();
 *    std::vector<SwTextAttr*> aAttrs
 *        = pTextNode->GetTextAttrsAt(rCursor.GetContentIndex(), RES_TXTATR_REFMARK);
 *
 *    auto& rRefmark = const_cast<SwFormatRefMark&>(aAttrs[0]->GetRefMark());
 *    auto pTextRefMark = const_cast<SwTextRefMark*>(rRefmark.GetTextRefMark());
 *
 *    // When typing after the refmark...
 *    pWrtShell->SttEndDoc(true);
 *    pWrtShell->Right(SwCursorSkipMode::Chars, false, 3, false);
 *    pWrtShell->Insert(" bar");
 *
 *    // and skipping back to insert a comma after the refmark
 *    pWrtShell->Left(SwCursorSkipMode::Chars, false, 4, false);
 *    pWrtShell->Insert(",");
 *
 *    // Without the accompanying fix in place, this test would have failed with:
 *    // - Expected: 3
 *    // - Actual  : 4
 *    // i.e. the reference mark expanded
 *    CPPUNIT_ASSERT_EQUAL(3, static_cast<int>(*pTextRefMark->End()));
 *}
 */


CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testInsertDropDownContentControlTwice)
{
    // Given an already selected dropdown content control:
    createSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);

    // When trying to insert an inner one, make sure that we don't crash:
    pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testCheckboxContentControlKeyboard)
{
    // Given an already selected checkbox content control:
    createSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX);
    SwEditWin& rEditWin = pWrtShell->GetView().GetEditWin();

    // When pressing space on the keyboard:
    KeyEvent aKeyEvent(' ', KEY_SPACE);
    rEditWin.KeyInput(aKeyEvent);

    // Then make sure the state is toggled:
    SwTextNode* pTextNode = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
    SwTextAttr* pAttr = pTextNode->GetTextAttrForCharAt(0, RES_TXTATR_CONTENTCONTROL);
    auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
    auto& rFormatContentControl
        = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
    std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
    // Without the accompanying fix in place, this test would have failed, because the state
    // remained unchanged.
    CPPUNIT_ASSERT(pContentControl->GetChecked());
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testDropdownContentControlKeyboard)
{
    // Given an already selected dropdown content control:
    createSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->InsertContentControl(SwContentControlType::DROP_DOWN_LIST);

    // When checking if alt-down should open a popup:
    SwTextContentControl* pTextContentControl = pWrtShell->CursorInsideContentControl();
    auto& rFormatContentControl
        = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
    std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
    vcl::KeyCode aKeyCode(KEY_DOWN, KEY_MOD2);
    bool bShouldOpen = pContentControl->ShouldOpenPopup(aKeyCode);

    // Then make sure that the answer is yes for dropdowns:
    // Without the accompanying fix in place, this test would have failed, the dropdown popup was
    // mouse-only.
    CPPUNIT_ASSERT(bShouldOpen);
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testPictureContentControlKeyboard)
{
    // Given an already selected picture content control:
    createSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->InsertContentControl(SwContentControlType::PICTURE);
    pWrtShell->GotoObj(/*bNext=*/true, GotoObjFlags::Any);

    // When checking if enter should trigger the file picker:
    const SwFrameFormat* pFlyFormat = pWrtShell->GetFlyFrameFormat();
    const SwFormatAnchor& rFormatAnchor = pFlyFormat->GetAnchor();
    SwNode* pAnchorNode = rFormatAnchor.GetAnchorNode();
    SwTextNode* pTextNode = pAnchorNode->GetTextNode();
    SwTextAttr* pAttr
        = pTextNode->GetTextAttrAt(rFormatAnchor.GetAnchorContentOffset(),
                                   RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent);
    auto pTextContentControl = static_txtattr_cast<SwTextContentControl*>(pAttr);
    auto& rFormatContentControl
        = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
    std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
    bool bIsInteracting = pContentControl->IsInteractingCharacter('\r');

    // Then make sure that the answer is yes for pictures:
    // Without the accompanying fix in place, this test would have failed, the picture replacement
    // file-picker was mouse-only.
    CPPUNIT_ASSERT(bIsInteracting);
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testDateContentControlKeyboard)
{
    // Given an already selected date content control:
    createSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->InsertContentControl(SwContentControlType::DATE);

    // When checking if alt-down should open a popup:
    SwTextContentControl* pTextContentControl = pWrtShell->CursorInsideContentControl();
    auto& rFormatContentControl
        = static_cast<SwFormatContentControl&>(pTextContentControl->GetAttr());
    std::shared_ptr<SwContentControl> pContentControl = rFormatContentControl.GetContentControl();
    vcl::KeyCode aKeyCode(KEY_DOWN, KEY_MOD2);
    bool bShouldOpen = pContentControl->ShouldOpenPopup(aKeyCode);

    // Then make sure that the answer is yes for date:
    // Without the accompanying fix in place, this test would have failed, the date popup was
    // mouse-only.
    CPPUNIT_ASSERT(bShouldOpen);
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testContentControlCopy)
{
    // Given a document with a content control:
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->InsertContentControl(SwContentControlType::CHECKBOX);

    // When copying that content control:
    pWrtShell->SelAll();
    rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
    xTransfer->Copy();
    // Kill the selection, go to the end of the document:
    pWrtShell->EndOfSection();
    TransferableDataHelper aHelper(xTransfer);
    SwTransferable::Paste(*pWrtShell, aHelper);

    // Then make sure that the copy is also a checkbox:
    SwContentControlManager& rManager = pDoc->GetContentControlManager();
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rManager.GetCount());
    const SwFormatContentControl& rFormat1 = rManager.Get(0)->GetContentControl();
    CPPUNIT_ASSERT_EQUAL(SwContentControlType::CHECKBOX, rFormat1.GetContentControl()->GetType());
    const SwFormatContentControl& rFormat2 = rManager.Get(1)->GetContentControl();
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: 1 (CHECKBOX)
    // - Actual  : 0 (RICH_TEXT)
    // i.e. properties were not copied from the source to the destination content control.
    CPPUNIT_ASSERT_EQUAL(SwContentControlType::CHECKBOX, rFormat2.GetContentControl()->GetType());
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTdf157287)
{
    createSwDoc("tdf157287.odt");
    uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
    auto xFieldsAccess(xTextFieldsSupplier->getTextFields());
    uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
    uno::Reference<text::XTextField> xField(xFields->nextElement(), uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(u"30"_ustr, xField->getPresentation(false));

    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xIndexAccess(xTextTablesSupplier->getTextTables(),
                                                         uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTextTable(xIndexAccess->getByIndex(0), uno::UNO_QUERY);

    uno::Reference<text::XTextRange> xCellA1(xTextTable->getCellByName(u"B1"_ustr), uno::UNO_QUERY);
    xCellA1->setString(u"100"_ustr);

    dispatchCommand(mxComponent, u".uno:UpdateFields"_ustr, {});

    // Without the fix in place, this test would have failed with
    // - Expected: 120
    // - Actual  :
    CPPUNIT_ASSERT_EQUAL(u"120"_ustr, xField->getPresentation(false));
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testFlySplitFootnote)
{
    // Given a document with a split fly (to host a table):
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    SwFlyFrameAttrMgr aMgr(true, pWrtShell, Frmmgr_Type::TEXT, nullptr);
    RndStdIds eAnchor = RndStdIds::FLY_AT_PARA;
    pWrtShell->StartAllAction();
    aMgr.InsertFlyFrame(eAnchor, aMgr.GetPos(), aMgr.GetSize());
    pWrtShell->EndAllAction();
    pWrtShell->StartAllAction();
    sw::FrameFormats<sw::SpzFrameFormat*>& rFlys = *pDoc->GetSpzFrameFormats();
    sw::SpzFrameFormat* pFly = rFlys[0];
    SwAttrSet aSet(pFly->GetAttrSet());
    aSet.Put(SwFormatFlySplit(true));
    pDoc->SetAttr(aSet, *pFly);
    pWrtShell->EndAllAction();
    pWrtShell->UnSelectFrame();
    pWrtShell->LeaveSelFrameMode();
    pWrtShell->GetView().AttrChangedNotify(nullptr);
    pWrtShell->MoveSection(GoCurrSection, fnSectionEnd);

    // When inserting a footnote:
    pWrtShell->InsertFootnote(OUString());

    // Then make sure the footnote gets inserted to the doc model.
    // Without the accompanying fix in place, this test would have failed, insert code refused to
    // have footnotes in all fly frames.
    CPPUNIT_ASSERT(!pDoc->GetFootnoteIdxs().empty());
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testSplitFlyAnchorSplit)
{
    // Given a document with a 2 pages long floating table:
    createSwDoc("floattable-anchor-split.docx");

    // When splitting the "AB" anchor text into "A" (remains as anchor text) and "B" (new text node
    // after it):
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->SttEndDoc(/*bStt=*/false);
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 1, /*bBasicCall=*/false);
    // Without the accompanying fix in place, this test would have failed with a layout loop.
    pWrtShell->SplitNode();

    // Then make sure the resulting layout is what we want:
    SwDoc* pDoc = getSwDoc();
    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
    auto pPage1 = pLayout->Lower()->DynCastPageFrame();
    CPPUNIT_ASSERT(pPage1);
    // Page 1 has the master fly:
    CPPUNIT_ASSERT(pPage1->GetSortedObjs());
    auto pPage2 = pPage1->GetNext()->DynCastPageFrame();
    CPPUNIT_ASSERT(pPage2);
    // Page 2 has the follow fly:
    CPPUNIT_ASSERT(pPage2->GetSortedObjs());
    // Anchor text is now just "A":
    auto pText1 = pPage2->FindFirstBodyContent()->DynCastTextFrame();
    CPPUNIT_ASSERT_EQUAL(u"A"_ustr, pText1->GetText());
    // New text frame is just "B":
    auto pText2 = pText1->GetNext()->DynCastTextFrame();
    CPPUNIT_ASSERT_EQUAL(u"B"_ustr, pText2->GetText());

    // Also test that the new follow anchor text frame still has a fly portion, otherwise the anchor
    // text and the floating table would overlap:
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    OUString aPortionType = getXPath(
        pXmlDoc, "//page[2]/body/txt[1]/SwParaPortion/SwLineLayout[1]/child::*[1]", "type");
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: PortionType::Fly
    // - Actual  : PortionType::Para
    // i.e. the fly portion was missing, text overlapped.
    CPPUNIT_ASSERT_EQUAL(u"PortionType::Fly"_ustr, aPortionType);
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testPlainContentControlCopy)
{
    // Given a document with a plain text content control, all text selected and copied to the
    // clipboard:
    createSwDoc("plain-content-control-copy.docx");
    SwDocShell* pDocShell = getSwDocShell();
    SwWrtShell* pWrtShell = pDocShell->GetWrtShell();
    pWrtShell->SelAll();
    {
        rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
        xTransfer->Copy();
    }

    // When closing that document, then make sure we don't crash on shutdown:
    uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
    uno::Reference<util::XCloseable> xFrame(xModel->getCurrentController()->getFrame(),
                                            uno::UNO_QUERY);
    // Without the accompanying fix in place, this resulted in an assertion failure, a char style
    // still had clients by the time it was deleted.
    xFrame->close(false);
    mxComponent.clear();
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testCopyCommentsWithReplies)
{
    createSwDoc("comment-reply-copy.odt");

    SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
    SwDocShell* pShell = pTextDoc->GetDocShell();
    SwWrtShell* pWrtShell = pShell->GetWrtShell();
    SwDoc aClipboard;
    pWrtShell->SelAll();
    pWrtShell->Copy(aClipboard);
    pWrtShell->SttEndDoc(/*bStart=*/false); // Send the cursor to the end of the document.
    pWrtShell->Paste(aClipboard);

    // Now we have selected all text (which is one line) and pasted it to the end.
    // A comment and its reply should also be copied to the end of the document.
    // We will check if our reply is referencing its copied parent instead of the source parent.

    SwPostItMgr* postItManager = pWrtShell->GetPostItMgr();

    std::vector<const SwPostItField*> comments;

    Scheduler::ProcessEventsToIdle();

    for (const auto& pItem : *postItManager) // There should be 4.
    {
        comments.push_back(pItem->mpPostIt->GetPostItField());
    }

    //                   parents (original-copied), replies (original-copied)
    CPPUNIT_ASSERT_EQUAL(comments[0]->GetName().toString(),
                         comments[1]->GetParentName().toString());
    CPPUNIT_ASSERT_EQUAL(comments[2]->GetName().toString(),
                         comments[3]->GetParentName().toString());
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testNodeSplitStyleListLevel)
{
    // Given a document with a 3rd paragraph where the list level as direct formatting differs from
    // the list level from style:
    createSwDoc("node-split-style-list-level.odt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->Down(/*bSelect=*/false, /*nCount=*/2);
    pWrtShell->EndPara();

    // When pressing enter at the end of the paragraph:
    pWrtShell->SplitNode();

    SwTextNode* pNext = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
    // Without the accompanying fix in place, this test would have failed with:
    // - Expected: 4
    // - Actual  : 3
    // i.e. the list level for the new paragraph changed on a simple node split.
    CPPUNIT_ASSERT_EQUAL(4, pNext->GetAttrListLevel());
    pWrtShell->Up(/*bSelect=*/false, /*nCount=*/1);
    SwTextNode* pPrevious = pWrtShell->GetCursor()->GetPointNode().GetTextNode();
    // Same happened for the old paragraph.
    CPPUNIT_ASSERT_EQUAL(4, pPrevious->GetAttrListLevel());
}

CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testDOCXCommentImport)
{
    // Given a DOCX file with a comment in it:
    // When loading that file:
    createSwDoc("comment.docx");

    // Then make sure that the postit field has a name that matches the name of an annotation mark:
    SwDoc* pDoc = getSwDoc();
    const SwFieldTypes* pFieldTypes = pDoc->getIDocumentFieldsAccess().GetFieldTypes();
    const SwFieldType* pPostitFieldType = nullptr;
    for (const auto& pFieldType : *pFieldTypes)
    {
        if (pFieldType->Which() == SwFieldIds::Postit)
        {
            pPostitFieldType = pFieldType.get();
            break;
        }
    }
    CPPUNIT_ASSERT(pPostitFieldType);
    std::vector<SwFormatField*> aFormatPostits;
    pPostitFieldType->GatherFields(aFormatPostits);
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aFormatPostits.size());
    const SwFormatField* pFormatPostit = aFormatPostits[0];
    auto pPostit = static_cast<const SwPostItField*>(pFormatPostit->GetField());
    IDocumentMarkAccess* pMarkAccess = pDoc->getIDocumentMarkAccess();
    auto it = pMarkAccess->findAnnotationMark(pPostit->GetName());
    // Without the accompanying fix in place, this test would have failed, there were no annotation
    // marks with the name of pPostit.
    CPPUNIT_ASSERT(it != pMarkAccess->getAnnotationMarksEnd());
}

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=80 H=97 G=88

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.