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

Quelle  uiwriter.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 <com/sun/star/awt/FontWeight.hpp>
#include <com/sun/star/document/XDocumentInsertable.hpp>
#include <com/sun/star/drawing/GraphicExportFilter.hpp>
#include <com/sun/star/i18n/TextConversionOption.hpp>
#include <swmodeltestbase.hxx>
#include <ndtxt.hxx>
#include <wrtsh.hxx>
#include <shellio.hxx>
#include <expfld.hxx>
#include <drawdoc.hxx>
#include <redline.hxx>
#include <fmtclds.hxx>
#include <dcontact.hxx>
#include <view.hxx>
#include <hhcwrp.hxx>
#include <swacorr.hxx>
#include <swmodule.hxx>
#include <modcfg.hxx>
#include <editeng/acorrcfg.hxx>
#include <unotools/streamwrap.hxx>
#include <unocrsrhelper.hxx>
#include <com/sun/star/text/VertOrientation.hpp>
#include <com/sun/star/text/XDefaultNumberingProvider.hpp>
#include <com/sun/star/text/XTextTable.hpp>
#include <vcl/TypeSerializer.hxx>

#include <svx/svdpage.hxx>
#include <svx/svdview.hxx>
#include <svx/svxids.hrc>

#include <editeng/eeitem.hxx>
#include <editeng/scriptsetitem.hxx>
#include <editeng/wghtitem.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <UndoManager.hxx>
#include <frmatr.hxx>

#include <com/sun/star/text/TextMarkupType.hpp>
#include <osl/file.hxx>
#include <comphelper/propertysequence.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/dispatch.hxx>
#include <vcl/scheduler.hxx>
#include <sfx2/watermarkitem.hxx>
#include <sfx2/docfile.hxx>
#include <fmthdft.hxx>
#include <iodetect.hxx>
#include <comphelper/processfactory.hxx>
#include <unotxdoc.hxx>
#include <swdtflvr.hxx>
#include <sortedobjs.hxx>
#include <rootfrm.hxx>
#include <txtfrm.hxx>

namespace
{
void lcl_selectCharacters(SwPaM& rPaM, sal_Int32 first, sal_Int32 end)
{
    rPaM.GetPoint()->nContent.Assign(rPaM.GetPointContentNode(), first);
    rPaM.SetMark();
    rPaM.GetPoint()->nContent.Assign(rPaM.GetPointContentNode(), end);
}
//namespace

class SwUiWriterTest : public SwModelTestBase
{
public:
    SwUiWriterTest() :
        SwModelTestBase(u"/sw/qa/extras/uiwriter/data/"_ustr)
    {}

    std::unique_ptr<SwTextBlocks> readDOCXAutotext(
        std::u16string_view sFileName, bool bEmpty = false);
    void testRedlineFrame(char const*const file);
};

std::unique_ptr<SwTextBlocks> SwUiWriterTest::readDOCXAutotext(std::u16string_view sFileName, bool bEmpty)
{
    createTempCopy(sFileName);

    SfxMedium aSrcMed(maTempFile.GetURL(), StreamMode::STD_READ);
    createSwDoc();
    SwDoc* pDoc = getSwDoc();

    SwReader aReader(aSrcMed, maTempFile.GetURL(), pDoc);
    Reader* pDOCXReader = SwReaderWriter::GetDOCXReader();
    auto pGlossary = std::make_unique<SwTextBlocks>(maTempFile.GetURL());

    CPPUNIT_ASSERT(pDOCXReader != nullptr);
    CPPUNIT_ASSERT_EQUAL(!bEmpty, aReader.ReadGlossaries(*pDOCXReader, *pGlossary, false));

    return pGlossary;
}

void SwUiWriterTest::testRedlineFrame(char const*const file)
{
    createSwDoc(file);
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // there is exactly one frame
    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    RedlineFlags nMode = pWrtShell->GetRedlineFlags();
    CPPUNIT_ASSERT(nMode & RedlineFlags::ShowDelete);

    // hide delete redlines
    pWrtShell->SetRedlineFlags(nMode & ~RedlineFlags::ShowDelete);

    // there is still exactly one frame
    CPPUNIT_ASSERT_EQUAL(1, getShapes());

    pWrtShell->SetRedlineFlags(nMode); // show again

    // there is still exactly one frame
    CPPUNIT_ASSERT_EQUAL(1, getShapes());
}

//Replacement tests

constexpr OUString ORIGINAL_REPLACE_CONTENT(u"toto titi tutu"_ustr);
constexpr OUString EXPECTED_REPLACE_CONTENT(u"toto toto tutu"_ustr);

// Chinese conversion tests

const sal_Unicode CHINESE_TRADITIONAL_CONTENT(0x9F8D);
const sal_Unicode CHINESE_SIMPLIFIED_CONTENT(0x9F99);
constexpr OUString NON_CHINESE_CONTENT(u"Hippopotamus"_ustr);

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testReplaceForward)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();

    sw::UndoManager& rUndoManager = pDoc->GetUndoManager();

    SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
    SwPaM aPaM(aIdx);

    pDoc->getIDocumentContentOperations().InsertString(aPaM, ORIGINAL_REPLACE_CONTENT);

    SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
    lcl_selectCharacters(aPaM, 5, 9);
    pDoc->getIDocumentContentOperations().ReplaceRange(aPaM, u"toto"_ustr, false);

    CPPUNIT_ASSERT_EQUAL(EXPECTED_REPLACE_CONTENT, pTextNode->GetText());

    rUndoManager.Undo();

    CPPUNIT_ASSERT_EQUAL(ORIGINAL_REPLACE_CONTENT, pTextNode->GetText());
}


CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtCharStartOutside0)
{
    testRedlineFrame("redlineFrame.fodt");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtCharStartOutside)
{
    testRedlineFrame("redlineFrame_at_char_start_outside.fodt");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtCharStartInside)
{
    testRedlineFrame("redlineFrame_at_char_start_inside.fodt");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtParaStartOutside)
{
    testRedlineFrame("redline_fly_duplication_at_para_start_outside.fodt");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtParaEndInside)
{
    testRedlineFrame("redline_fly_duplication_at_para_end_inside.fodt");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtParaOneParagraph)
{
    // test ALLFLYS flag: oddly enough it didn't fail as fodt but failed as odt...
    testRedlineFrame("redline_fly_at_para_one_paragraph.odt");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testRedlineFrameAtPara2ndParagraph)
{
    // lost via the buggy increment in Copy
    testRedlineFrame("redline_fly_duplication_at_para_2nd_paragraph.fodt");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testThreadedException)
{
    SvFileStream aFileStream(createFileURL(u"threadedException.fodt"), StreamMode::READ);

    //threaded reading only kicks in if there is sufficient buffer to make it worthwhile, so read
    //from a SvFileStream to ensure that
    bool bRes = TestImportFODT(aFileStream);

    CPPUNIT_ASSERT(!bRes);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf149595)
{
    createSwDoc("demo91.fodt");

    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // all 4 shapes are on the 2nd paragraph
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() == nullptr);
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr);
    CPPUNIT_ASSERT_EQUAL(size_t(4), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size());

    {
        pWrtShell->Down(false);
        pWrtShell->EndPara(/*bSelect=*/true);
        dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});

        // one shape is anchored in the middle, others at the start/end/at-para
        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() == nullptr);
        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr);
        CPPUNIT_ASSERT_EQUAL(size_t(3), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size());

        pWrtShell->Up(false);
        dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() != nullptr);
        CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs()->size());
        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr);
        CPPUNIT_ASSERT_EQUAL(size_t(3), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size());

        pWrtShell->Undo();
        pWrtShell->Undo();

        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() == nullptr);
        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr);
        CPPUNIT_ASSERT_EQUAL(size_t(4), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size());
    }

    // now try the same with redlining enabled - should be the same result
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    {
        pWrtShell->Down(false);
        pWrtShell->SttPara(/*bSelect=*/false);
        pWrtShell->EndPara(/*bSelect=*/true);
        dispatchCommand(mxComponent, u".uno:Cut"_ustr, {});

        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() == nullptr);
        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr);
        // problem was that this deleted all at-char flys, even at the start/end
        CPPUNIT_ASSERT_EQUAL(size_t(3), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size());

        pWrtShell->Up(false);
        dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});

        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() != nullptr);
        CPPUNIT_ASSERT_EQUAL(size_t(1), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs()->size());
        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr);
        CPPUNIT_ASSERT_EQUAL(size_t(3), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size());

        pWrtShell->Undo();
        pWrtShell->Undo();

        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetDrawObjs() == nullptr);
        CPPUNIT_ASSERT(pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs() != nullptr);
        CPPUNIT_ASSERT_EQUAL(size_t(4), pWrtShell->GetLayout()->GetLower()->GetLower()->GetLower()->GetNext()->GetDrawObjs()->size());
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf149548)
{
    createSwDoc("forum-mso-en-13192-min.docx");
    SwDoc* pDoc = getSwDoc();

    for (SwRangeRedline const*const pRedline : pDoc->getIDocumentRedlineAccess().GetRedlineTable())
    {
        if (pRedline->GetType() == RedlineType::Delete)
        {
            int nLevel(0);
            for (SwNodeIndex index = pRedline->Start()->nNode; index <= pRedline->End()->nNode; ++index)
            {
                switch (index.GetNode().GetNodeType())
                {
                    case SwNodeType::Start:
                    case SwNodeType::Table:
                    case SwNodeType::Section:
                        ++nLevel;
                        break;
                    case SwNodeType::End:
                        CPPUNIT_ASSERT_MESSAGE("bad overlapping redline", nLevel != 0);
                        --nLevel;
                        break;
                    default:
                        break;
                }
            }
            CPPUNIT_ASSERT_EQUAL_MESSAGE("bad overlapping redline"int(0), nLevel);
        }
    }

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

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

    // this was a use-after-free on nodes deleted by Copy
    dispatchCommand(mxComponent, u".uno:Paste"_ustr, {});
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testPasteTableAtFlyAnchor)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
    anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
    SfxItemSet flySet(pDoc->GetAttrPool(), svl::Items<RES_ANCHOR, RES_ANCHOR>);
    flySet.Put(anchor);
    SwFlyFrameFormat const* pFly = dynamic_cast<SwFlyFrameFormat const*>(
            pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true));
    CPPUNIT_ASSERT(pFly != nullptr);
    CPPUNIT_ASSERT(pFly->GetFrame() != nullptr);
    pWrtShell->SelFlyGrabCursor();
    pWrtShell->GetDrawView()->UnmarkAll();
    CPPUNIT_ASSERT(pWrtShell->GetCurrFlyFrame() != nullptr);

    // insert table in fly
    SwInsertTableOptions tableOpt(SwInsertTableFlags::DefaultBorder, 0);
    pWrtShell->InsertTable(tableOpt, 2, 2);

    // select table
    pWrtShell->SelAll();

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

    // move cursor back to body
    pWrtShell->ClearMark();
    pWrtShell->SttEndDoc(/*bStt=*/true);
    CPPUNIT_ASSERT(!pWrtShell->GetCurrFlyFrame());

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

    pWrtShell->SttEndDoc(/*bStt=*/true);
    CPPUNIT_ASSERT(pWrtShell->IsCursorInTable());
    CPPUNIT_ASSERT(!pFly->GetAnchor().GetContentAnchor()->GetNode().FindTableNode());

    pWrtShell->Undo();

    pWrtShell->SttEndDoc(/*bStt=*/true);
    CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
    CPPUNIT_ASSERT(!pFly->GetAnchor().GetContentAnchor()->GetNode().FindTableNode());

    // the problem was that Redo moved the fly anchor into the first table cell
    pWrtShell->Redo();

    pWrtShell->SttEndDoc(/*bStt=*/true);
    CPPUNIT_ASSERT(pWrtShell->IsCursorInTable());
    CPPUNIT_ASSERT(!pFly->GetAnchor().GetContentAnchor()->GetNode().FindTableNode());

    pWrtShell->Undo();

    pWrtShell->SttEndDoc(/*bStt=*/true);
    CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());
    CPPUNIT_ASSERT(!pFly->GetAnchor().GetContentAnchor()->GetNode().FindTableNode());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testCopyPastePageBreak)
{
    createSwDoc("pagebreak-source.fodt");

    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT_EQUAL(tools::Long(5669), pWrtShell->GetLayout()->GetLower()->getFramePrintArea().Top());

    pWrtShell->SelAll();
    dispatchCommand(mxComponent, u".uno:Copy"_ustr, {});

    createSwDoc("pagebreak-target.fodt");
    SwDoc* pDoc = getSwDoc();
    pWrtShell = getSwDocShell()->GetWrtShell();

    CPPUNIT_ASSERT_EQUAL(1, getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"WithMargin"_ustr, getProperty<OUString>(getParagraph(1), u"PageDescName"_ustr));
    CPPUNIT_ASSERT_EQUAL(u"TargetSection"_ustr, pWrtShell->GetCurrSection()->GetSectionName().toString());
    // page style WithMargin is used
    CPPUNIT_ASSERT_EQUAL(tools::Long(5669), pWrtShell->GetLayout()->GetLower()->getFramePrintArea().Top());

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

    CPPUNIT_ASSERT_EQUAL(2, getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"WithMargin"_ustr, getProperty<OUString>(getParagraph(1), u"PageDescName"_ustr));
    CPPUNIT_ASSERT_EQUAL(size_t(2), pDoc->GetSections().size());
    CPPUNIT_ASSERT_EQUAL(u"SourceSection"_ustr, pWrtShell->GetCurrSection()->GetSectionName().toString());
    // the problem was that there was a page break now
    CPPUNIT_ASSERT_EQUAL(1, getPages());
    // page style WithMargin is used
    CPPUNIT_ASSERT_EQUAL(tools::Long(5669), pWrtShell->GetLayout()->GetLower()->getFramePrintArea().Top());

    pWrtShell->Undo();
    CPPUNIT_ASSERT_EQUAL(1, getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"WithMargin"_ustr, getProperty<OUString>(getParagraph(1), u"PageDescName"_ustr));
    CPPUNIT_ASSERT_EQUAL(u"TargetSection"_ustr, pWrtShell->GetCurrSection()->GetSectionName().toString());
    CPPUNIT_ASSERT_EQUAL(1, getPages());
    // page style WithMargin is used
    CPPUNIT_ASSERT_EQUAL(tools::Long(5669), pWrtShell->GetLayout()->GetLower()->getFramePrintArea().Top());

    pWrtShell->Redo();
    CPPUNIT_ASSERT_EQUAL(2, getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"WithMargin"_ustr, getProperty<OUString>(getParagraph(1), u"PageDescName"_ustr));
    CPPUNIT_ASSERT_EQUAL(size_t(2), pDoc->GetSections().size());
    CPPUNIT_ASSERT_EQUAL(u"SourceSection"_ustr, pWrtShell->GetCurrSection()->GetSectionName().toString());
    CPPUNIT_ASSERT_EQUAL(1, getPages());
    // page style WithMargin is used
    CPPUNIT_ASSERT_EQUAL(tools::Long(5669), pWrtShell->GetLayout()->GetLower()->getFramePrintArea().Top());

    pWrtShell->Undo();
    CPPUNIT_ASSERT_EQUAL(1, getParagraphs());
    CPPUNIT_ASSERT_EQUAL(u"WithMargin"_ustr, getProperty<OUString>(getParagraph(1), u"PageDescName"_ustr));
    CPPUNIT_ASSERT_EQUAL(u"TargetSection"_ustr, pWrtShell->GetCurrSection()->GetSectionName().toString());
    CPPUNIT_ASSERT_EQUAL(1, getPages());
    // page style WithMargin is used
    CPPUNIT_ASSERT_EQUAL(tools::Long(5669), pWrtShell->GetLayout()->GetLower()->getFramePrintArea().Top());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testBookmarkCopy)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();

    // add text and bookmark
    IDocumentMarkAccess & rIDMA(*pDoc->getIDocumentMarkAccess());
    IDocumentContentOperations & rIDCO(pDoc->getIDocumentContentOperations());
    SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
    SwCursor aPaM(SwPosition(aIdx), nullptr);
    rIDCO.InsertString(aPaM, u"foo"_ustr);
    rIDCO.SplitNode(*aPaM.GetPoint(), false);
    rIDCO.InsertString(aPaM, u"bar"_ustr);
    aPaM.SetMark();
    aPaM.MovePara(GoCurrPara, fnParaStart);
    rIDMA.makeMark(aPaM, SwMarkName(u"Mark"_ustr), IDocumentMarkAccess::MarkType::BOOKMARK,
            ::sw::mark::InsertMode::New);
    aPaM.Exchange();
    aPaM.DeleteMark();
    rIDCO.SplitNode(*aPaM.GetPoint(), false);
    rIDCO.InsertString(aPaM, u"baz"_ustr);

    // copy range
    rIDCO.SplitNode(*aPaM.GetPoint(), false);
    SwPosition target(*aPaM.GetPoint());
    aPaM.Move(fnMoveBackward, GoInContent);
    aPaM.SetMark();
    aPaM.SttEndDoc(true/*start*/);
    aPaM.Move(fnMoveForward, GoInContent); // partially select 1st para

    rIDCO.CopyRange(aPaM, target, SwCopyFlags::CheckPosInFly);

    // check bookmark was copied to correct position
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), rIDMA.getBookmarksCount());
    for (auto it(rIDMA.getBookmarksBegin()); it != rIDMA.getBookmarksEnd(); ++it)
    {
        OUString markText(SwPaM((*it)->GetMarkPos(), (*it)->GetOtherMarkPos()).GetText());
        CPPUNIT_ASSERT_EQUAL(u"bar"_ustr, markText);
    }

    // copy 2nd time, such that bCanMoveBack is false in CopyImpl
    SwPaM aCopyPaM(*aPaM.GetMark(), *aPaM.GetPoint());
    aPaM.SttEndDoc(true/*start*/);
    rIDCO.SplitNode(*aPaM.GetPoint(), false);
    aPaM.SttEndDoc(true/*start*/);

    rIDCO.CopyRange(aCopyPaM, *aPaM.GetPoint(), SwCopyFlags::CheckPosInFly);

    // check bookmark was copied to correct position
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), rIDMA.getBookmarksCount());
    for (auto it(rIDMA.getBookmarksBegin()); it != rIDMA.getBookmarksEnd(); ++it)
    {
        OUString markText(SwPaM((*it)->GetMarkPos(), (*it)->GetOtherMarkPos()).GetText());
        CPPUNIT_ASSERT_EQUAL(u"bar"_ustr, markText);
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFormulaNumberWithGroupSeparator)
{
    createSwDoc("tdf125154.odt");
    dispatchCommand(mxComponent, u".uno:UpdateAll"_ustr, {});
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->SttEndDoc(true);
    SwField const* pField;

    pField = pWrtShell->GetCurField();
    CPPUNIT_ASSERT_EQUAL(u"1000"_ustr, pField->GetFormula());
    CPPUNIT_ASSERT_EQUAL(u"1.000"_ustr, pField->ExpandField(true, nullptr));
    pWrtShell->GoNextCell();
    CPPUNIT_ASSERT_EQUAL(u"10000"_ustr, pWrtShell->GetCursor()->GetPoint()->nNode.GetNode().GetTextNode()->GetText());
    pWrtShell->GoNextCell();
    pField = pWrtShell->GetCurField();
    CPPUNIT_ASSERT_EQUAL(u"test"_ustr, pField->GetFormula());
    CPPUNIT_ASSERT_EQUAL(u"1.000"_ustr, pField->ExpandField(true, nullptr));
    pWrtShell->GoNextCell();
    // the problem was that this was 0
    CPPUNIT_ASSERT_EQUAL(u"10000"_ustr, pWrtShell->GetCursor()->GetPoint()->nNode.GetNode().GetTextNode()->GetText());
    pWrtShell->Down(false);
    pWrtShell->SttPara(false);
    pField = pWrtShell->GetCurField();
    CPPUNIT_ASSERT_EQUAL(u"1000*10%"_ustr, pField->GetFormula());
    CPPUNIT_ASSERT_EQUAL(u"100"_ustr, pField->ExpandField(true, nullptr));
    pWrtShell->Down(false);
    pField = pWrtShell->GetCurField();
    CPPUNIT_ASSERT_EQUAL(u"5.000*10%"_ustr, pField->GetFormula());
    // the problem was that this was 0
    CPPUNIT_ASSERT_EQUAL(u"500"_ustr, pField->ExpandField(true, nullptr));
    pWrtShell->Down(false);
    pField = pWrtShell->GetCurField();
    CPPUNIT_ASSERT_EQUAL(u"5.000*10%"_ustr, pField->GetFormula());
    // the problem was that this was
    CPPUNIT_ASSERT_EQUAL(u"500"_ustr, pField->ExpandField(true, nullptr));
    pWrtShell->Down(false);
    pField = pWrtShell->GetCurField();
    CPPUNIT_ASSERT_EQUAL(u"5000*10%"_ustr, pField->GetFormula());
    CPPUNIT_ASSERT_EQUAL(u"500"_ustr, pField->ExpandField(true, nullptr));
    pWrtShell->Down(false);
    CPPUNIT_ASSERT_EQUAL(u"-100,00 €"_ustr, pWrtShell->GetCursor()->GetPoint()->nNode.GetNode().GetTextNode()->GetText());
    pWrtShell->GoNextCell();
    // tdf#42518 the problem was that this was 1.900,00 €
    CPPUNIT_ASSERT_EQUAL(u"** Expression is faulty **"_ustr, pWrtShell->GetCursor()->GetPoint()->nNode.GetNode().GetTextNode()->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testInsertFileInInputFieldException)
{
    createSwDoc();
    uno::Reference<text::XTextDocument> const xTextDoc(mxComponent, uno::UNO_QUERY);
    uno::Reference<text::XText> const xBody(xTextDoc->getText());
    uno::Reference<lang::XMultiServiceFactory> const xFactory(mxComponent, uno::UNO_QUERY);
    uno::Reference<text::XTextCursor> const xCursor(xBody->createTextCursor());
    uno::Reference<document::XDocumentInsertable> const xInsertable(xCursor, uno::UNO_QUERY);
    uno::Reference<text::XTextContent> const xContent(
        xFactory->createInstance(u"com.sun.star.text.textfield.Input"_ustr), uno::UNO_QUERY);
    xBody->insertTextContent(xCursor, xContent, false);
    xCursor->goLeft(1, false);
    // try to insert some random file
    // inserting even asserts in debug builds - document model goes invalid with input field split across 2 nodes
    CPPUNIT_ASSERT_THROW(xInsertable->insertDocumentFromURL(createFileURL(u"fdo75110.odt"), {}), uno::RuntimeException);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf67238)
{
    //create a new writer document
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
    //insert a 3X3 table in the newly created document
    SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
    const SwTable& rTable = pWrtShell->InsertTable(TableOpt, 3, 3);
    //checking for the rows and columns
    uno::Reference<text::XTextTable> xTable(getParagraphOrTable(1), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable->getColumns()->getCount());
    //selecting the table
    pWrtShell->StartOfSection();
    pWrtShell->SelTable();
    //making the table protected
    pWrtShell->ProtectCells();
    //checking each cell's protection, it should be protected
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"A1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"A2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"A3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"B1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"B2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"B3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"C1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"C2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"C3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    //undo the changes, make cells [un]protected
    rUndoManager.Undo();
    //checking each cell's protection, it should be [un]protected
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"A1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"A2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"A3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"B1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"B2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"B3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"C1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"C2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"C3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    //redo the changes, make cells protected
    rUndoManager.Redo();
    //checking each cell's protection, it should be protected
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"A1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"A2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"A3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"B1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"B2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"B3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"C1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"C2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"C3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    //moving the cursor to the starting of the document
    pWrtShell->StartOfSection();
    //making the table [un]protected
    pWrtShell->SelTable();
    pWrtShell->UnProtectCells();
    //checking each cell's protection, it should be [un]protected
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"A1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"A2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"A3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"B1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"B2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"B3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"C1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"C2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"C3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    //undo the changes, make cells protected
    rUndoManager.Undo();
    //checking each cell's protection, it should be protected
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"A1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"A2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"A3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"B1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"B2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"B3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"C1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"C2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(((rTable.GetTableBox(u"C3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    //redo the changes, make cells [un]protected
    rUndoManager.Redo();
    //checking each cell's protection, it should be [un]protected
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"A1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"A2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"A3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"B1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"B2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"B3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"C1"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"C2"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
    CPPUNIT_ASSERT(!((rTable.GetTableBox(u"C3"_ustr))->GetFrameFormat()->GetProtect()).IsContentProtected());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf155685)
{
    createSwDoc("table-at-end-of-cell.fodt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->GoNextCell();
    pWrtShell->GoNextCell();
    pWrtShell->GoNextCell();
    pWrtShell->SelAll();
    pWrtShell->Delete();
    // this crashed
    pWrtShell->Undo();
    pWrtShell->Undo();
    pWrtShell->Redo();
    // this crashed
    pWrtShell->Redo();
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf147220)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    pWrtShell->Insert(u"él"_ustr);

    // hide and enable
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT(pDoc->getIDocumentRedlineAccess().IsRedlineOn());
    CPPUNIT_ASSERT(
        IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    pWrtShell->GoStartSentence();
    pWrtShell->SetMark();
    pWrtShell->GoEndSentence();

    // this did not remove the original text from the layout
    pWrtShell->Replace(u"Él"_ustr, false);

    // currently the deleted text is before the replacement text, not sure if
    // that is really required
    CPPUNIT_ASSERT_EQUAL(u"élÉl"_ustr,
        pWrtShell->GetCursor()->GetPoint()->GetNode().GetTextNode()->GetText());
    CPPUNIT_ASSERT_EQUAL(u"Él"_ustr,
        static_cast<SwTextFrame const*>(pWrtShell->GetCursor()->GetPoint()->GetNode().GetTextNode()->getLayoutFrame(nullptr))->GetText());

    SwRedlineTable const& rRedlines(pDoc->getIDocumentRedlineAccess().GetRedlineTable());
    CPPUNIT_ASSERT_EQUAL(SwRedlineTable::size_type(2), rRedlines.size());
    CPPUNIT_ASSERT_EQUAL(RedlineType::Delete, rRedlines[0]->GetType());
    CPPUNIT_ASSERT_EQUAL(u"él"_ustr, rRedlines[0]->GetText());
    CPPUNIT_ASSERT_EQUAL(RedlineType::Insert, rRedlines[1]->GetType());
    CPPUNIT_ASSERT_EQUAL(u"Él"_ustr, rRedlines[1]->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf135978)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    pWrtShell->Insert(u"foobar"_ustr);
    pWrtShell->SplitNode();
    pWrtShell->Insert(u"bazquux"_ustr);

    CPPUNIT_ASSERT(pWrtShell->IsEndOfDoc());

    SwFormatAnchor anchor(RndStdIds::FLY_AT_CHAR);
    anchor.SetAnchor(pWrtShell->GetCursor()->GetPoint());
    SfxItemSet flySet(pDoc->GetAttrPool(), svl::Items<RES_ANCHOR, RES_ANCHOR>);
    flySet.Put(anchor);
    SwFlyFrameFormat const* pFly = dynamic_cast<SwFlyFrameFormat const*>(
            pWrtShell->NewFlyFrame(flySet, /*bAnchValid=*/true));
    CPPUNIT_ASSERT(pFly != nullptr);
    CPPUNIT_ASSERT(pFly->GetFrame() != nullptr);
    // move cursor back to body
    pWrtShell->SttEndDoc(/*bStt=*/false);

    // hide and enable
    dispatchCommand(mxComponent, u".uno:ShowTrackedChanges"_ustr, {});
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});

    CPPUNIT_ASSERT(pDoc->getIDocumentRedlineAccess().IsRedlineOn());
    CPPUNIT_ASSERT(
        IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));
    CPPUNIT_ASSERT(pWrtShell->GetLayout()->IsHideRedlines());

    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 4, /*bBasicCall=*/false);
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 6, /*bBasicCall=*/false);
    pWrtShell->Delete();

    // now split
    pWrtShell->SttEndDoc(/*bStt=*/true);
    pWrtShell->SplitNode();
    CPPUNIT_ASSERT(pFly->GetFrame() != nullptr);

    // the problem was that undo removed the fly frame from the layout
    pWrtShell->Undo();
    CPPUNIT_ASSERT(pFly->GetFrame() != nullptr);

    pWrtShell->Redo();
    CPPUNIT_ASSERT(pFly->GetFrame() != nullptr);

    pWrtShell->Undo();
    CPPUNIT_ASSERT(pFly->GetFrame() != nullptr);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo75110)
{
    createSwDoc("fdo75110.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    pWrtShell->SelAll();
    // The problem was that SwEditShell::DeleteSel() what this Delete() invokes took the wrong selection...
    pWrtShell->Delete();
    sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
    // ... so this Undo() call resulted in a crash.
    rUndoManager.Undo();
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo75898)
{
    createSwDoc("fdo75898.odt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->SelAll();
    pWrtShell->InsertRow(1, true);
    pWrtShell->InsertRow(1, true);

    // Now check if the table has 3 lines.
    SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
    SwTableNode* pTableNode = pShellCursor->Start()->GetNode().FindTableNode();
    // This was 1, when doing the same using the UI, Writer even crashed.
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pTableNode->GetTable().GetTabLines().size());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testReplaceBackward)
{
    //Regression test of fdo#70143
    //EDITING: undo search&replace corrupt text when searching backward
    createSwDoc();
    SwDoc* pDoc = getSwDoc();

    sw::UndoManager& rUndoManager = pDoc->GetUndoManager();

    SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
    SwPaM aPaM(aIdx);

    pDoc->getIDocumentContentOperations().InsertString(aPaM, u"toto titi tutu"_ustr);
    SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
    lcl_selectCharacters(aPaM, 9, 5);

    pDoc->getIDocumentContentOperations().ReplaceRange(aPaM, u"toto"_ustr, false);

    CPPUNIT_ASSERT_EQUAL(EXPECTED_REPLACE_CONTENT, pTextNode->GetText());

    rUndoManager.Undo();

    CPPUNIT_ASSERT_EQUAL(ORIGINAL_REPLACE_CONTENT, pTextNode->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo69893)
{
    createSwDoc("fdo69893.odt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    pWrtShell->SelAll(); // A1 is empty -> selects the whole table.
    pWrtShell->SelAll(); // Selects the whole document.

    SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
    SwTextNode& rEnd = dynamic_cast<SwTextNode&>(pShellCursor->End()->GetNode());
    // Selection did not include the para after table, this was "B1".
    CPPUNIT_ASSERT_EQUAL(u"Para after table."_ustr, rEnd.GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo70807)
{
    createSwDoc("fdo70807.odt");

    uno::Reference<container::XIndexAccess> xStylesIter(getStyles(u"PageStyles"_ustr), uno::UNO_QUERY);

    for (sal_Int32 i = 0; i < xStylesIter->getCount(); ++i)
    {
        uno::Reference<style::XStyle> xStyle(xStylesIter->getByIndex(i), uno::UNO_QUERY);

        bool expectedUsedStyle = false;
        bool expectedUserDefined = false;

        OUString styleName(xStyle->getName());

        // just these styles are user defined styles
        if (styleName == "pagestyle1" || styleName == "pagestyle2")
            expectedUserDefined = true;

        // just these styles are used in the document
        if (styleName == "Right Page" || styleName == "pagestyle1" || styleName == "pagestyle2")
            expectedUsedStyle = true;

        CPPUNIT_ASSERT_EQUAL(expectedUserDefined, bool(xStyle->isUserDefined()));
        CPPUNIT_ASSERT_EQUAL(expectedUsedStyle, bool(xStyle->isInUse()));
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testImportRTF)
{
    // Insert "foobar" and position the cursor between "foo" and "bar".
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->Insert(u"foobar"_ustr);
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 3, /*bBasicCall=*/false);

    // Insert the RTF at the cursor position.
    OString aData = "{\\rtf1 Hello world!\\par}"_ostr;
    SvMemoryStream aStream(const_cast<char*>(aData.getStr()), aData.getLength(), StreamMode::READ);
    SwReader aReader(aStream, OUString(), OUString(), *pWrtShell->GetCursor());
    Reader* pRTFReader = SwReaderWriter::GetRtfReader();
    CPPUNIT_ASSERT(pRTFReader != nullptr);
    CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, aReader.Read(*pRTFReader).GetCode());

    SwNodeOffset nIndex = pWrtShell->GetCursor()->GetPointNode().GetIndex();
    CPPUNIT_ASSERT_EQUAL(u"fooHello world!"_ustr, pDoc->GetNodes()[nIndex - 1]->GetTextNode()->GetText());
    CPPUNIT_ASSERT_EQUAL(u"bar"_ustr, pDoc->GetNodes()[nIndex]->GetTextNode()->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testExportRTF)
{
    // Insert "aaabbbccc" and select "bbb".
    createSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->Insert(u"aaabbbccc"_ustr);
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/false, 3, /*bBasicCall=*/false);
    pWrtShell->Left(SwCursorSkipMode::Chars, /*bSelect=*/true, 3, /*bBasicCall=*/false);

    // Create the clipboard document.
    rtl::Reference<SwDoc> xClpDoc(new SwDoc());
    xClpDoc->SetClipBoard(true);
    pWrtShell->Copy(*xClpDoc);

    // And finally export it as RTF.
    WriterRef xWrt;
    SwReaderWriter::GetWriter(u"RTF", OUString(), xWrt);
    SvMemoryStream aStream;
    SwWriter aWrt(aStream, *xClpDoc);
    aWrt.Write(xWrt);

    OString aData(static_cast<const char*>(aStream.GetData()), aStream.GetSize());

    //Amusingly eventually there was a commit id with "ccc" in it, and so the rtf contained
    //{\*\generator LibreOfficeDev/4.4.0.0.alpha0$Linux_X86_64 LibreOffice_project/f70664ccc6837f2cc21a29bb4f44e41e100efe6b}
    //so the test fell over. so strip the generator tag
    sal_Int32 nGeneratorStart = aData.indexOf("{\\*\\generator ");
    CPPUNIT_ASSERT(nGeneratorStart != -1);
    sal_Int32 nGeneratorEnd = aData.indexOf('}', nGeneratorStart + 1);
    CPPUNIT_ASSERT(nGeneratorEnd != -1);
    aData = aData.replaceAt(nGeneratorStart, nGeneratorEnd-nGeneratorStart+1, "");

    CPPUNIT_ASSERT(aData.startsWith("{\\rtf1"));
    CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), aData.indexOf("aaa"));
    CPPUNIT_ASSERT(aData.indexOf("bbb") != -1);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), aData.indexOf("ccc"));
    // Ensure there's no extra newline
    CPPUNIT_ASSERT(aData.endsWith("bbb}" SAL_NEWLINE_STRING "}"));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testDOCXAutoTextEmpty)
{
    // file contains normal content but no AutoText
    std::unique_ptr<SwTextBlocks> pGlossary = readDOCXAutotext(u"autotext-empty.dotx"true);
    CPPUNIT_ASSERT(pGlossary != nullptr);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testDOCXAutoTextMultiple)
{
    // file contains three AutoText entries
    std::unique_ptr<SwTextBlocks> pGlossary = readDOCXAutotext(u"autotext-multiple.dotx");

    // check entries count
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(3), pGlossary->GetCount());

    // check names of entries, sorted order
    CPPUNIT_ASSERT_EQUAL(u"Anothercomplex"_ustr, pGlossary->GetLongName(0));
    CPPUNIT_ASSERT_EQUAL(u"Multiple"_ustr, pGlossary->GetLongName(1));
    CPPUNIT_ASSERT_EQUAL(u"Second Autotext"_ustr, pGlossary->GetLongName(2));

    // check if previously loaded content is correct (eg. doesn't contain title)
    SwDoc* pDoc = pGlossary->GetDoc();
    CPPUNIT_ASSERT(pDoc != nullptr);

    SwNodeIndex aDocEnd(pDoc->GetNodes().GetEndOfContent());
    SwNodeIndex aStart(*aDocEnd.GetNode().StartOfSectionNode(), 1);

    CPPUNIT_ASSERT(aStart < aDocEnd);

    // first line
    SwNode& rNode = aStart.GetNode();
    CPPUNIT_ASSERT(rNode.IsTextNode());
    SwTextNode& rTextNode = *rNode.GetTextNode();
    CPPUNIT_ASSERT_EQUAL(u"Another "_ustr, rTextNode.GetText());

    // Make sure that autotext does not set a custom page style, leading to an unexpected page break
    // on insertion.
    // Without the accompanying fix in place, this test would have failed: the text node had an
    // attribute set containing a page style item.
    CPPUNIT_ASSERT(!rTextNode.HasSwAttrSet() || !rTextNode.GetSwAttrSet().HasItem(RES_PAGEDESC));

    // last line
    SwNodeIndex aLast(*aDocEnd.GetNode().EndOfSectionNode(), -1);
    SwNode& rLastNode = aLast.GetNode();
    CPPUNIT_ASSERT_EQUAL(u"complex"_ustr, rLastNode.GetTextNode()->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testDOTMAutoText)
{
    // this is dotm file difference is that in the dotm
    // there are no empty paragraphs at the end of each entry
    std::unique_ptr<SwTextBlocks> pGlossary = readDOCXAutotext(u"autotext-dotm.dotm");

    SwDoc* pDoc = pGlossary->GetDoc();
    CPPUNIT_ASSERT(pDoc != nullptr);

    // check if content is correct
    SwNodeIndex aDocEnd(pDoc->GetNodes().GetEndOfContent());
    SwNodeIndex aStart(*aDocEnd.GetNode().StartOfSectionNode(), 1);
    SwNode& rNode = aStart.GetNode();
    CPPUNIT_ASSERT_EQUAL(u"paragraph"_ustr, rNode.GetTextNode()->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testDOCXAutoTextGallery)
{
    // this file contains one AutoText entry and other
    // entries which are not AutoText (have different "gallery" value)
    std::unique_ptr<SwTextBlocks> pGlossary = readDOCXAutotext(u"autotext-gallery.dotx");

    SwDoc* pDoc = pGlossary->GetDoc();
    CPPUNIT_ASSERT(pDoc != nullptr);

    // check entries count
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(1), pGlossary->GetCount());

    // check entry name (if not contains gallery type)
    CPPUNIT_ASSERT_EQUAL(u"Multiple"_ustr, pGlossary->GetLongName(0));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testWatermarkDOCX)
{
    createSwDoc("watermark.docx");
    SwDocShell* pDocShell = getSwDocShell();
    SfxPoolItemHolder aResult;
    SfxItemState eState = pDocShell->GetViewShell()->GetViewFrame().GetDispatcher()->QueryState(SID_WATERMARK, aResult);
    const SfxWatermarkItem* pWatermark(static_cast<const SfxWatermarkItem*>(aResult.getItem()));

    CPPUNIT_ASSERT(eState >= SfxItemState::DEFAULT);
    CPPUNIT_ASSERT(pWatermark);
    CPPUNIT_ASSERT_EQUAL(static_cast<unsigned short>(SID_WATERMARK), pWatermark->Which());

    CPPUNIT_ASSERT_EQUAL(u"CustomWatermark"_ustr, pWatermark->GetText());
    CPPUNIT_ASSERT_EQUAL(u"DejaVu Sans Light"_ustr, pWatermark->GetFont());
    CPPUNIT_ASSERT_EQUAL(sal_Int16(45), pWatermark->GetAngle());
    CPPUNIT_ASSERT_EQUAL(Color(0x548dd4), pWatermark->GetColor());
    CPPUNIT_ASSERT_EQUAL(sal_Int16(50), pWatermark->GetTransparency());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testWatermarkPosition)
{
    // tdf#108494 Watermark inserted in the document with page break was outside the first page
    const int aPagesInDocument = 2;
    const int aAdditionalPagesCount[] = {    0,     0,    1,     1,    5,     5,   20,    20 };
    const bool aChangeHeader[]        = { truefalsetruefalsetruefalsetruefalse };

    for (tools::ULong i = 0; i < sizeof(aAdditionalPagesCount) / sizeof(int); ++i)
    {
        int aPages = aPagesInDocument + aAdditionalPagesCount[i];

        // Empty document with one Page Break
        createSwDoc("watermark-position.odt");
        SwDoc* pDoc = getSwDoc();
        SwEditShell* pEditShell = pDoc->GetEditShell();
        CPPUNIT_ASSERT(pEditShell);
        SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
        uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(mxComponent,
                                                                         uno::UNO_QUERY);
        uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();

        // 1. Add additional page breaks
        for (int j = 0; j < aAdditionalPagesCount[i]; ++j)
            pWrtShell->InsertPageBreak();

        // 2. Change header state (On, Off, On)
        if (aChangeHeader[i])
        {
            SwPageDesc aDesc(pDoc->GetPageDesc(0));
            SwFrameFormat& rMaster = aDesc.GetMaster();
            rMaster.SetFormatAttr(SwFormatHeader(true));
            pDoc->ChgPageDesc(0, aDesc);

            aDesc = pDoc->GetPageDesc(0);
            SwFrameFormat& rMaster2 = aDesc.GetMaster();
            rMaster2.SetFormatAttr(SwFormatHeader(false));
            pDoc->ChgPageDesc(0, aDesc);

            aDesc = pDoc->GetPageDesc(0);
            SwFrameFormat& rMaster3 = aDesc.GetMaster();
            rMaster3.SetFormatAttr(SwFormatHeader(true));
            pDoc->ChgPageDesc(0, aDesc);
        }

        // 3. Insert Watermark
        SfxWatermarkItem aWatermark;
        aWatermark.SetText(u"Watermark"_ustr);
        aWatermark.SetFont(u"DejaVu Sans"_ustr);

        pEditShell->SetWatermark(aWatermark);

        uno::Reference<css::drawing::XShape> xShape = getShape(1);
        CPPUNIT_ASSERT(xShape.is());

        SdrPage* pPage = pWrtShell->GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);

        // Get Watermark object
        SdrObject* pObject = pPage->GetObj(0);
        pObject->RecalcBoundRect();
        const tools::Rectangle& rRect = pObject->GetSnapRect();
        Size rSize = pPage->GetSize();

        // Page break, calculate height of a page
        const int nPageHeight = rSize.getHeight() / aPages;

        std::stringstream aMessage;
        aMessage << "Case: " << i << ", nPageHeight = " << nPageHeight << ", rRect.Bottom = " << rRect.Bottom();

        // Check if Watermark is inside a page
        CPPUNIT_ASSERT_MESSAGE(aMessage.str(), nPageHeight >= rRect.Bottom());

        // Check if Watermark is centered
        CPPUNIT_ASSERT_EQUAL(text::HoriOrientation::CENTER, getProperty<sal_Int16>(xShape, u"HoriOrient"_ustr));
        CPPUNIT_ASSERT_EQUAL(text::VertOrientation::CENTER, getProperty<sal_Int16>(xShape, u"VertOrient"_ustr));
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo74981)
{
    // create a document with an input field
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    SwInputField aField(static_cast<SwInputFieldType*>(pWrtShell->GetFieldType(0, SwFieldIds::Input)), u"foo"_ustr, u"bar"_ustr, 0, 0);
    pWrtShell->InsertField2(aField);

    {
        // expect hints
        SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
        SwTextNode* pTextNode = aIdx.GetNode().GetTextNode();
        CPPUNIT_ASSERT(pTextNode->HasHints());
    }

    // go to the begin of the paragraph and split this node
    pWrtShell->Left(SwCursorSkipMode::Chars, false, 100, false);
    pWrtShell->SplitNode();

    {
        // expect only the second paragraph to have hints
        SwNodeIndex aIdx(SwNodeIndex(pDoc->GetNodes().GetEndOfContent(), -1));
        SwTextNode* pTextNode = aIdx.GetNode().GetTextNode();
        CPPUNIT_ASSERT(pTextNode->HasHints());
        --aIdx;
        pTextNode = aIdx.GetNode().GetTextNode();
        CPPUNIT_ASSERT(!pTextNode->HasHints());
    }
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTdf98512)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    SwInputFieldType *const pType(static_cast<SwInputFieldType*>(
                pWrtShell->GetFieldType(0, SwFieldIds::Input)));
    SwInputField aField1(pType, u"foo"_ustr, u"bar"_ustr, INP_TXT, 0);
    pWrtShell->InsertField2(aField1);
    pWrtShell->SttEndDoc(/*bStt=*/true);
    SwInputField aField2(pType, u"baz"_ustr, u"quux"_ustr, INP_TXT, 0);
    pWrtShell->InsertField2(aField2);
    pWrtShell->SttEndDoc(/*bStt=*/true);
    pWrtShell->SetMark();
    pWrtShell->SttEndDoc(/*bStt=*/false);
    OUString const expected1(
        OUStringChar(CH_TXT_ATR_INPUTFIELDSTART) + "foo" + OUStringChar(CH_TXT_ATR_INPUTFIELDEND));
    OUString const expected2(
        OUStringChar(CH_TXT_ATR_INPUTFIELDSTART) + "baz" + OUStringChar(CH_TXT_ATR_INPUTFIELDEND)
        + expected1);
    CPPUNIT_ASSERT_EQUAL(expected2, pWrtShell->getShellCursor(false)->GetText());
    sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
    rUndoManager.Undo();
    pWrtShell->SttEndDoc(/*bStt=*/true);
    pWrtShell->SetMark();
    pWrtShell->SttEndDoc(/*bStt=*/false);
    CPPUNIT_ASSERT_EQUAL(expected1, pWrtShell->getShellCursor(false)->GetText());
    rUndoManager.Redo();
    pWrtShell->SttEndDoc(/*bStt=*/true);
    pWrtShell->SetMark();
    pWrtShell->SttEndDoc(/*bStt=*/false);
    CPPUNIT_ASSERT_EQUAL(expected2, pWrtShell->getShellCursor(false)->GetText());
    rUndoManager.Undo();
    pWrtShell->SttEndDoc(/*bStt=*/true);
    pWrtShell->SetMark();
    pWrtShell->SttEndDoc(/*bStt=*/false);
    CPPUNIT_ASSERT_EQUAL(expected1, pWrtShell->getShellCursor(false)->GetText());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testShapeTextboxSelect)
{
    createSwDoc("shape-textbox.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
    SdrObject* pObject = pPage->GetObj(1);
    SwContact* pTextBox = static_cast<SwContact*>(pObject->GetUserCall());
    // First, make sure that pTextBox is a fly frame (textbox of a shape).
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_FLYFRMFMT), pTextBox->GetFormat()->Which());

    // Then select it.
    pWrtShell->SelectObj(Point(), 0, pObject);
    const SdrMarkList& rMarkList = pWrtShell->GetDrawView()->GetMarkedObjectList();
    SwDrawContact* pShape = static_cast<SwDrawContact*>(rMarkList.GetMark(0)->GetMarkedSdrObj()->GetUserCall());
    // And finally make sure the shape got selected, not just the textbox itself.
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_DRAWFRMFMT), pShape->GetFormat()->Which());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testShapeTextboxDelete)
{
    createSwDoc("shape-textbox.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
    SdrObject* pObject = pPage->GetObj(0);
    pWrtShell->SelectObj(Point(), 0, pObject);
    size_t nActual = pPage->GetObjCount();
    // Two objects on the draw page: the shape and its textbox.
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), nActual);

    pWrtShell->DelSelectedObj();
    nActual = pPage->GetObjCount();
    // Both (not only the shape) should be removed by now (the textbox wasn't removed, so this was 1).
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), nActual);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testAnchorChangeSelection)
{
    createSwDoc("test_anchor_as_character.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
    SdrObject* pObject = pPage->GetObj(0);
    CPPUNIT_ASSERT(pObject);

    // Then select it.
    pWrtShell->SelectObj(Point(), 0, pObject);
    const SdrMarkList& rMarkList = pWrtShell->GetDrawView()->GetMarkedObjectList();
    CPPUNIT_ASSERT_EQUAL(pObject, rMarkList.GetMark(0)->GetMarkedSdrObj());

    pWrtShell->ChgAnchor(RndStdIds::FLY_AS_CHAR);

    // tdf#125039 shape must still be selected, extensions depend on that
    CPPUNIT_ASSERT_EQUAL(pObject, rMarkList.GetMark(0)->GetMarkedSdrObj());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testCp1000071)
{
    createSwDoc("cp1000071.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    const SwRedlineTable& rTable = pDoc->getIDocumentRedlineAccess().GetRedlineTable();
    CPPUNIT_ASSERT_EQUAL( SwRedlineTable::size_type( 2 ), rTable.size());
    SwNodeOffset redlineStart0NodeIndex = rTable[ 0 ]->Start()->GetNodeIndex();
    sal_Int32 redlineStart0Index = rTable[ 0 ]->Start()->GetContentIndex();
    SwNodeOffset redlineEnd0NodeIndex = rTable[ 0 ]->End()->GetNodeIndex();
    sal_Int32 redlineEnd0Index = rTable[ 0 ]->End()->GetContentIndex();
    SwNodeOffset redlineStart1NodeIndex = rTable[ 1 ]->Start()->GetNodeIndex();
    sal_Int32 redlineStart1Index = rTable[ 1 ]->Start()->GetContentIndex();
    SwNodeOffset redlineEnd1NodeIndex = rTable[ 1 ]->End()->GetNodeIndex();
    sal_Int32 redlineEnd1Index = rTable[ 1 ]->End()->GetContentIndex();

    // Change the document layout to be 2 columns, and then undo.
    pWrtShell->SelAll();
    SwSectionData section(SectionType::Content, UIName(pWrtShell->GetUniqueSectionName()));
    SfxItemSet set( getSwDocShell()->GetPool(), svl::Items<RES_COL, RES_COL> );
    SwFormatCol col;
    col.Init( 2, 0, 10000 );
    set.Put( col );
    pWrtShell->InsertSection( section, &set );
    sw::UndoManager& rUndoManager = pDoc->GetUndoManager();
    rUndoManager.Undo();

    // Check that redlines are the same like at the beginning.
    CPPUNIT_ASSERT_EQUAL( SwRedlineTable::size_type( 2 ), rTable.size());
    CPPUNIT_ASSERT_EQUAL( redlineStart0NodeIndex, rTable[ 0 ]->Start()->GetNodeIndex());
    CPPUNIT_ASSERT_EQUAL( redlineStart0Index, rTable[ 0 ]->Start()->GetContentIndex());
    CPPUNIT_ASSERT_EQUAL( redlineEnd0NodeIndex, rTable[ 0 ]->End()->GetNodeIndex());
    CPPUNIT_ASSERT_EQUAL( redlineEnd0Index, rTable[ 0 ]->End()->GetContentIndex());
    CPPUNIT_ASSERT_EQUAL( redlineStart1NodeIndex, rTable[ 1 ]->Start()->GetNodeIndex());
    CPPUNIT_ASSERT_EQUAL( redlineStart1Index, rTable[ 1 ]->Start()->GetContentIndex());
    CPPUNIT_ASSERT_EQUAL( redlineEnd1NodeIndex, rTable[ 1 ]->End()->GetNodeIndex());
    CPPUNIT_ASSERT_EQUAL( redlineEnd1Index, rTable[ 1 ]->End()->GetContentIndex());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testShapeTextboxVertadjust)
{
    createSwDoc("shape-textbox-vertadjust.odt");
    SwDoc* pDoc = getSwDoc();
    SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
    SdrObject* pObject = pPage->GetObj(1);
    SwFrameFormat* pFormat = static_cast<SwContact*>(pObject->GetUserCall())->GetFormat();
    // This was SDRTEXTVERTADJUST_TOP.
    CPPUNIT_ASSERT_EQUAL(SDRTEXTVERTADJUST_CENTER, pFormat->GetTextVertAdjust().GetValue());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testShapeTextboxAutosize)
{
    createSwDoc("shape-textbox-autosize.odt");
    SwDoc* pDoc = getSwDoc();
    SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
    // 0-1 is the first UI-visible shape+textbox.
    SdrObject* pFirst = pPage->GetObj(0);
    CPPUNIT_ASSERT_EQUAL(u"1st"_ustr, pFirst->GetName());

    // 2-3 is the second UI-visible shape+textbox.
    SdrObject* pSecond = pPage->GetObj(2);
    CPPUNIT_ASSERT_EQUAL(u"2nd"_ustr, pSecond->GetName());

    // Shape -> textbox synchronization was missing, the second shape had the
    // same height as the first, even though the first contained 1 paragraph
    // and the other 2 ones.
    CPPUNIT_ASSERT(pFirst->GetSnapRect().getOpenHeight() < pSecond->GetSnapRect().getOpenHeight());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo82191)
{
    createSwDoc("fdo82191.odt");
    SwDoc* pDoc = getSwDoc();
    SdrPage* pPage = pDoc->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0);
    // Make sure we have a single draw shape.
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), SwTextBoxHelper::getCount(pPage));

    SwDoc aClipboard;
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    SdrObject* pObject = pPage->GetObj(0);
    // Select it, then copy and paste.
    pWrtShell->SelectObj(Point(), 0, pObject);
    pWrtShell->Copy(aClipboard);
    pWrtShell->Paste(aClipboard);

    // This was one: the textbox of the shape wasn't copied.
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), SwTextBoxHelper::getCount(*pDoc));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testCommentedWord)
{
    // This word is commented. <- string in document
    // 123456789 <- character positions
    createSwDoc("commented-word.odt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    // Move the cursor into the second word.
    pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/false, 5, /*bBasicCall=*/false);
    // Select the word.
    pWrtShell->SelWrd();

    // Make sure that not only the word, but its comment anchor is also selected.
    SwShellCursor* pShellCursor = pWrtShell->getShellCursor(false);
    // This was 9, only "word", not "word<anchor character>" was selected.
    CPPUNIT_ASSERT_EQUAL(sal_Int32(10), pShellCursor->End()->GetContentIndex());

    // Test that getAnchor() points to "word", not to an empty string.
    uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
    uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
    uno::Reference<text::XTextContent> xField(xFields->nextElement(), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"word"_ustr, xField->getAnchor()->getString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testTextFieldGetAnchorGetTextInFooter)
{
    createSwDoc("textfield-getanchor-gettext-in-footer.odt");

    uno::Reference<text::XTextFieldsSupplier> xTextFieldsSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XEnumerationAccess> xFieldsAccess(xTextFieldsSupplier->getTextFields());
    uno::Reference<container::XEnumeration> xFields(xFieldsAccess->createEnumeration());
    uno::Reference<text::XTextContent> xField(xFields->nextElement(), uno::UNO_QUERY);

    OUString value = xField->getAnchor()->getText()->getString();
    CPPUNIT_ASSERT_EQUAL(u"userfield_in_footer"_ustr, value );
}

// Tests that a blank document is still blank after conversion
CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testChineseConversionBlank)
{

    // Given
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwView* pView = getSwDocShell()->GetView();
    const uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
    SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
    SwPaM aPaM(aIdx);

    // When
    SwHHCWrapper aWrap( *pView, xContext, LANGUAGE_CHINESE_TRADITIONAL, LANGUAGE_CHINESE_SIMPLIFIED, nullptr,
                        i18n::TextConversionOption::CHARACTER_BY_CHARACTER, false,
                        truefalsefalse );
    aWrap.Convert();

    // Then
    SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
    CPPUNIT_ASSERT_EQUAL(OUString(), pTextNode->GetText());

}

// Tests that non Chinese text is unchanged after conversion
CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testChineseConversionNonChineseText)
{

    // Given
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwView* pView = getSwDocShell()->GetView();
    const uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
    SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
    SwPaM aPaM(aIdx);
    pDoc->getIDocumentContentOperations().InsertString(aPaM, NON_CHINESE_CONTENT);

    // When
    SwHHCWrapper aWrap( *pView, xContext, LANGUAGE_CHINESE_TRADITIONAL, LANGUAGE_CHINESE_SIMPLIFIED, nullptr,
                        i18n::TextConversionOption::CHARACTER_BY_CHARACTER, false,
                        truefalsefalse );
    aWrap.Convert();

    // Then
    SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
    CPPUNIT_ASSERT_EQUAL(NON_CHINESE_CONTENT, pTextNode->GetText());

}

// Tests conversion of traditional Chinese characters to simplified Chinese
CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testChineseConversionTraditionalToSimplified)
{

    // Given
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwView* pView = getSwDocShell()->GetView();
    const uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
    SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
    SwPaM aPaM(aIdx);
    pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(CHINESE_TRADITIONAL_CONTENT));

    // When
    SwHHCWrapper aWrap( *pView, xContext, LANGUAGE_CHINESE_TRADITIONAL, LANGUAGE_CHINESE_SIMPLIFIED, nullptr,
                        i18n::TextConversionOption::CHARACTER_BY_CHARACTER, false,
                        truefalsefalse );
    aWrap.Convert();

    // Then
    SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
    CPPUNIT_ASSERT_EQUAL(OUString(CHINESE_SIMPLIFIED_CONTENT), pTextNode->GetText());

}

// Tests conversion of simplified Chinese characters to traditional Chinese
CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testChineseConversionSimplifiedToTraditional)
{

    // Given
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwView* pView = getSwDocShell()->GetView();
    const uno::Reference< uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
    SwNodeIndex aIdx(pDoc->GetNodes().GetEndOfContent(), -1);
    SwPaM aPaM(aIdx);
    pDoc->getIDocumentContentOperations().InsertString(aPaM, OUString(CHINESE_SIMPLIFIED_CONTENT));

    // When
    SwHHCWrapper aWrap( *pView, xContext, LANGUAGE_CHINESE_SIMPLIFIED, LANGUAGE_CHINESE_TRADITIONAL, nullptr,
                        i18n::TextConversionOption::CHARACTER_BY_CHARACTER, false,
                        truefalsefalse );
    aWrap.Convert();

    // Then
    SwTextNode* pTextNode = aPaM.GetPointNode().GetTextNode();
    CPPUNIT_ASSERT_EQUAL(OUString(CHINESE_TRADITIONAL_CONTENT), pTextNode->GetText());

}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testFdo85554)
{
    // Load the document, it contains one shape with a textbox.
    createSwDoc("fdo85554.odt");

    // Add a second shape to the document.
    uno::Reference<css::lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
    uno::Reference<drawing::XShape> xShape(xFactory->createInstance(u"com.sun.star.drawing.RectangleShape"_ustr), uno::UNO_QUERY);
    xShape->setSize(awt::Size(10000, 10000));
    xShape->setPosition(awt::Point(1000, 1000));
    uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
    xDrawPage->add(xShape);

    // Save it and load it back.
    saveAndReload(u"writer8"_ustr);

    // This was 1, we lost a shape on export.
    CPPUNIT_ASSERT_EQUAL(2, getShapes());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testMergeDoc)
{
    createSwDoc("merge-change1.odt");
    SwDoc* pDoc = getSwDoc();

    mxComponent2 = loadFromDesktop(
            createFileURL(u"merge-change2.odt"),
            u"com.sun.star.text.TextDocument"_ustr);
    auto pxDoc2Document(
            dynamic_cast<SwXTextDocument *>(mxComponent2.get()));
    CPPUNIT_ASSERT(pxDoc2Document);
    SwDoc* const pDoc2(pxDoc2Document->GetDocShell()->GetDoc());

    SwEditShell* const pEditShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT(pEditShell);
    pEditShell->MergeDoc(*pDoc2);

    // accept all redlines
    while(pEditShell->GetRedlineCount())
        pEditShell->AcceptRedline(0);

    CPPUNIT_ASSERT_EQUAL(7, getParagraphs());
    getParagraph(1, u"Para One: Two Three Four Five"_ustr);
    getParagraph(2, u"Para Two: One Three Four Five"_ustr);
    getParagraph(3, u"Para Three: One Two Four Five"_ustr);
    getParagraph(4, u"Para Four: One Two Three Four Five"_ustr);
    getParagraph(5, u"Para Six: One Three Four Five"_ustr);
    getParagraph(6, u""_ustr);
    getParagraph(7, u""_ustr);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest, testCreatePortions)
{
    createSwDoc("uno-cycle.odt");
    uno::Reference<text::XBookmarksSupplier> xBookmarksSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<text::XTextContent> xText(xBookmarksSupplier->getBookmarks()->getByName(u"Mark"_ustr), uno::UNO_QUERY);
    uno::Reference<container::XEnumerationAccess> xTextCursor(xText->getAnchor(), uno::UNO_QUERY);
    CPPUNIT_ASSERT(xTextCursor.is());

    uno::Reference<container::XEnumerationAccess> xParagraph(
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=92 H=88 G=89

¤ Dauer der Verarbeitung: 0.27 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.