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 145 kB image not shown  

Quelle  uiwriter6.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/drawing/FillStyle.hpp>
#include <swmodeltestbase.hxx>
#include <cntfrm.hxx>
#include <itabenum.hxx>
#include <ndtxt.hxx>
#include <wrtsh.hxx>
#include <edtwin.hxx>
#include <drawdoc.hxx>
#include <view.hxx>
#include <com/sun/star/text/XTextColumns.hpp>

#include <svx/svdpage.hxx>
#include <svx/svdview.hxx>
#include <svl/itemiter.hxx>
#include <vcl/filter/PDFiumLibrary.hxx>

#include <dbfld.hxx>
#include <txatbase.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <IDocumentRedlineAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <UndoManager.hxx>

#include <svl/stritem.hxx>
#include <sfx2/viewfrm.hxx>
#include <sfx2/dispatch.hxx>
#include <cmdid.h>
#include <tools/json_writer.hxx>
#include <tools/UnitConversion.hxx>
#include <boost/property_tree/json_parser.hpp>

#include <com/sun/star/text/XTextTable.hpp>
#include <com/sun/star/text/XTextViewCursorSupplier.hpp>
#include <com/sun/star/view/XSelectionSupplier.hpp>
#include <o3tl/cppunittraitshelper.hxx>
#include <swdtflvr.hxx>
#include <comphelper/propertysequence.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/scopeguard.hxx>
#include <editeng/swafopt.hxx>
#include <editeng/unolingu.hxx>
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
#include <vcl/scheduler.hxx>
#include <config_fonts.h>
#include <test/htmltesttools.hxx>
#include <wrthtml.hxx>
#include <dbmgr.hxx>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <sortedobjs.hxx>
#include <flyfrms.hxx>
#include <tabfrm.hxx>
#include <unotxdoc.hxx>
#include <wrong.hxx>
#include <com/sun/star/linguistic2/LinguServiceManager.hpp>
#include <com/sun/star/linguistic2/XLinguProperties.hpp>
#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
#include <linguistic/misc.hxx>

#include <workctrl.hxx>

using namespace com::sun::star;
using namespace com::sun::star::beans;
using namespace com::sun::star::lang;
using namespace com::sun::star::uno;
using namespace com::sun::star::linguistic2;
using namespace linguistic;

namespace
{
sal_Int32 lcl_getAttributeIDFromHints(const SwpHints& hints)
{
    for (size_t i = 0; i < hints.Count(); ++i)
    {
        const SwTextAttr* hint = hints.Get(i);
        if (hint->Which() == RES_TXTATR_AUTOFMT)
        {
            const SwFormatAutoFormat& rFmt = hint->GetAutoFormat();
            SfxItemIter aIter(*rFmt.GetStyleHandle());
            return aIter.GetCurItem()->Which();
        }
    }
    return -1;
}

uno::Reference<XLinguServiceManager2> GetLngSvcMgr_Impl()
{
    uno::Reference<XComponentContext> xContext(comphelper::getProcessComponentContext());
    uno::Reference<XLinguServiceManager2> xRes = LinguServiceManager::create(xContext);
    return xRes;
}
//namespace

class SwUiWriterTest6 : public SwModelTestBase, public HtmlTestTools
{
public:
    SwUiWriterTest6()
        : SwModelTestBase(u"/sw/qa/extras/uiwriter/data/"_ustr)
    {
    }
};

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf116640)
{
    createSwDoc();

    uno::Sequence<beans::PropertyValue> aArgs(
        comphelper::InitPropertySequence({ { "Columns", uno::Any(sal_Int32(2)) } }));

    dispatchCommand(mxComponent, u".uno:InsertSection"_ustr, aArgs);

    uno::Reference<text::XTextSectionsSupplier> xTextSectionsSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xSections(xTextSectionsSupplier->getTextSections(),
                                                      uno::UNO_QUERY);
    uno::Reference<beans::XPropertySet> xTextSection(xSections->getByIndex(0), uno::UNO_QUERY);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());

    uno::Reference<text::XTextColumns> xTextColumns
        = getProperty<uno::Reference<text::XTextColumns>>(xTextSection, u"TextColumns"_ustr);
    CPPUNIT_ASSERT_EQUAL(sal_Int16(2), xTextColumns->getColumnCount());

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

    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xSections->getCount());

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

    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xSections->getCount());

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

    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xSections->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf108524)
{
    createSwDoc("tdf108524.odt");
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    // In total we expect two cells containing a section.
    assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/section", 2);

    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell/section", 1);
    // This was 0, section wasn't split, instead it was only on the first page
    // and it was cut off.
    assertXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell/section", 1);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testLinesInSectionInTable)
{
    // This is similar to testTdf108524(), but the page boundary now is not in
    // the middle of a multi-line paragraph: the section only contains oneliner
    // paragraphs instead.
    createSwDoc("lines-in-section-in-table.odt");
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    // In total we expect two cells containing a section.
    assertXPath(pXmlDoc, "/root/page/body/tab/row/cell/section", 2);

    assertXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell/section", 1);
    // This was 0, section wasn't split, instead it was only on the first page
    // and it was cut off.
    assertXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell/section", 1);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testLinesMoveBackwardsInSectionInTable)
{
#if HAVE_MORE_FONTS
    // Assert that paragraph "4" is on page 1 and "5" is on page 2.
    createSwDoc("lines-in-section-in-table.odt");
    SwDoc* pDoc = getSwDoc();
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "/root/page", 2);
    SwNodeOffset nPara4Node(
        getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/section/txt[last()]""txtNodeIndex")
            .toUInt32());
    CPPUNIT_ASSERT_EQUAL(u"4"_ustr, pDoc->GetNodes()[nPara4Node]->GetTextNode()->GetText());
    SwNodeOffset nPara5Node(
        getXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell[1]/section/txt[1]""txtNodeIndex")
            .toUInt32());
    CPPUNIT_ASSERT_EQUAL(u"5"_ustr, pDoc->GetNodes()[nPara5Node]->GetTextNode()->GetText());

    // Remove paragraph "4".
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    while (pWrtShell->GetCursor()->GetPointNode().GetIndex() < nPara4Node)
        pWrtShell->Down(/*bSelect=*/false);
    pWrtShell->EndPara();
    pWrtShell->Up(/*bSelect=*/true);
    pWrtShell->DelLeft();

    // Assert that paragraph "5" is now moved back to page 1 and is the last paragraph there.
    pXmlDoc = parseLayoutDump();
    SwNodeOffset nPage1LastNode(
        getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/section/txt[last()]""txtNodeIndex")
            .toUInt32());
    // This was "3", paragraph "4" was deleted, but "5" was not moved backwards from page 2.
    CPPUNIT_ASSERT_EQUAL(u"5"_ustr, pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTableInSection)
{
#if HAVE_MORE_FONTS
    // The document has a section, containing a table that spans over 2 pages.
    createSwDoc("table-in-sect.odt");
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    // In total we expect 4 cells.
    assertXPath(pXmlDoc, "/root/page/body/section/tab/row/cell", 4);

    // Assert that on both pages the section contains 2 cells.
    assertXPath(pXmlDoc, "/root/page[1]/body/section/tab/row/cell", 2);
    assertXPath(pXmlDoc, "/root/page[2]/body/section/tab/row/cell", 2);
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTableInNestedSection)
{
#if HAVE_MORE_FONTS
    // The document has a nested section, containing a table that spans over 2 pages.
    // This crashed the layout.
    createSwDoc("rhbz739252-3.odt");
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    // Make sure the table is inside a section and spans over 2 pages.
    assertXPath(pXmlDoc, "//page[1]//section/tab", 1);
    assertXPath(pXmlDoc, "//page[2]//section/tab", 1);
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112741)
{
#if HAVE_MORE_FONTS
    createSwDoc("tdf112741.fodt");
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    // This was 5 pages.
    assertXPath(pXmlDoc, "//page", 4);
    assertXPath(pXmlDoc, "//page[1]/body/tab/row/cell/tab/row/cell/section", 1);
    assertXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row/cell/section", 1);
    // This failed, 3rd page contained no sections.
    assertXPath(pXmlDoc, "//page[3]/body/tab/row/cell/tab/row/cell/section", 1);
    assertXPath(pXmlDoc, "//page[4]/body/tab/row/cell/tab/row/cell/section", 1);
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112860)
{
#if HAVE_MORE_FONTS
    // The document has a split section inside a nested table, and also a table
    // in the footer.
    // This crashed the layout.
    createSwDoc("tdf112860.fodt");
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113287)
{
#if HAVE_MORE_FONTS
    createSwDoc("tdf113287.fodt");
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "//page", 2);
    sal_uInt32 nCellTop
        = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell[1]/infos/bounds", "top").toUInt32();
    sal_uInt32 nSectionTop
        = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell[1]/section/infos/bounds", "top")
              .toUInt32();
    // Make sure section frame is inside the cell frame.
    // Expected greater than 4593, was only 3714.
    CPPUNIT_ASSERT_GREATER(nCellTop, nSectionTop);
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113445)
{
#if HAVE_MORE_FONTS
    // Force multiple-page view.
    createSwDoc("tdf113445.fodt");
    SwDocShell* pDocShell = getSwDocShell();
    SwView* pView = pDocShell->GetView();
    pView->SetViewLayout(/*nColumns=*/2, /*bBookMode=*/false);
    calcLayout();

    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "//page", 2);
    sal_uInt32 nPage1Left = getXPath(pXmlDoc, "//page[1]/infos/bounds", "left").toUInt32();
    sal_uInt32 nPage2Left = getXPath(pXmlDoc, "//page[2]/infos/bounds", "left").toUInt32();
    // Make sure that page 2 is on the right hand side of page 1, not below it.
    CPPUNIT_ASSERT_GREATER(nPage1Left, nPage2Left);

    // Insert a new paragraph at the start of the document.
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->StartOfSection();
    pWrtShell->SplitNode();
    pXmlDoc = parseLayoutDump();

    // Make sure that Table2:C5 and Table2:D5 has its section frame inside the cell frame.
    sal_uInt32 nCell3Top
        = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[3]/infos/bounds", "top")
              .toUInt32();
    sal_uInt32 nSection3Top
        = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[3]/section/infos/bounds",
                   "top")
              .toUInt32();
    CPPUNIT_ASSERT_GREATER(nCell3Top, nSection3Top);
    sal_uInt32 nCell4Top
        = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[4]/infos/bounds", "top")
              .toUInt32();
    sal_uInt32 nSection4Top
        = getXPath(pXmlDoc, "//page[2]/body/tab/row/cell/tab/row[4]/cell[4]/section/infos/bounds",
                   "top")
              .toUInt32();
    CPPUNIT_ASSERT_GREATER(nCell4Top, nSection4Top);
    // Also check if the two cells in the same row have the same top position.
    // This was 4818, expected only 1672.
    CPPUNIT_ASSERT_EQUAL(nCell3Top, nCell4Top);
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113686)
{
#if HAVE_MORE_FONTS
    createSwDoc("tdf113686.fodt");
    SwDoc* pDoc = getSwDoc();
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "/root/page", 2);
    SwNodeOffset nPage1LastNode(
        getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/tab/row/cell[1]/txt[last()]",
                 "txtNodeIndex")
            .toUInt32());
    CPPUNIT_ASSERT_EQUAL(u"Table2:A1-P10"_ustr,
                         pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
    SwNodeOffset nPage2FirstNode(
        getXPath(pXmlDoc, "/root/page[2]/body/tab/row/cell[1]/section/txt[1]""txtNodeIndex")
            .toUInt32());
    CPPUNIT_ASSERT_EQUAL(u"Table1:A1"_ustr,
                         pDoc->GetNodes()[nPage2FirstNode]->GetTextNode()->GetText());

    // Remove page 2.
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    while (pWrtShell->GetCursor()->Start()->GetNodeIndex() < nPage1LastNode)
        pWrtShell->Down(/*bSelect=*/false);
    pWrtShell->EndPara();
    for (int i = 0; i < 3; ++i)
        pWrtShell->Up(/*bSelect=*/true);
    pWrtShell->DelLeft();

    // Assert that the second page is removed.
    pXmlDoc = parseLayoutDump();
    // This was still 2, content from 2nd page was not moved.
    assertXPath(pXmlDoc, "/root/page", 1);
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTableInSectionInTable)
{
#if HAVE_MORE_FONTS
    // The document has a table, containing a section, containing a nested
    // table.
    // This crashed the layout.
    createSwDoc("i95698.odt");
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable)
{
#if HAVE_MORE_FONTS
    // The document has a nested table, containing a multi-line section at a
    // page boundary.
    // This crashed the layout later in SwFrame::IsFootnoteAllowed().
    createSwDoc("tdf112109.fodt");
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable2)
{
#if HAVE_MORE_FONTS
    createSwDoc("split-section-in-nested-table.fodt");
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    sal_uInt32 nSection1
        = getXPath(pXmlDoc, "//page[1]//body/tab/row/cell/tab/row/cell/section", "id").toUInt32();
    sal_uInt32 nSection1Follow
        = getXPath(pXmlDoc, "//page[1]//body/tab/row/cell/tab/row/cell/section", "follow")
              .toUInt32();
    // This failed, the section wasn't split inside a nested table.
    sal_uInt32 nSection2
        = getXPath(pXmlDoc, "//page[2]//body/tab/row/cell/tab/row/cell/section", "id").toUInt32();
    sal_uInt32 nSection2Precede
        = getXPath(pXmlDoc, "//page[2]//body/tab/row/cell/tab/row/cell/section", "precede")
              .toUInt32();

    // Make sure that the first's follow and the second's precede is correct.
    CPPUNIT_ASSERT_EQUAL(nSection2, nSection1Follow);
    CPPUNIT_ASSERT_EQUAL(nSection1, nSection2Precede);
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable3)
{
#if HAVE_MORE_FONTS
    createSwDoc("tdf113153.fodt");

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
                                                    uno::UNO_QUERY);
    uno::Reference<container::XNamed> xTable(xTables->getByIndex(1), uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(u"Table16"_ustr, xTable->getName());

    uno::Reference<text::XTextTable> xRowSupplier(xTable, uno::UNO_QUERY);
    uno::Reference<table::XTableRows> xRows = xRowSupplier->getRows();
    uno::Reference<beans::XPropertySet> xRow(xRows->getByIndex(1), uno::UNO_QUERY);
    xRow->setPropertyValue(u"IsSplitAllowed"_ustr, uno::Any(true));
    // This never returned.
    calcLayout();

    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    sal_uInt32 nTable1 = getXPath(pXmlDoc, "//page[1]//body/tab", "id").toUInt32();
    sal_uInt32 nTable1Follow = getXPath(pXmlDoc, "//page[1]//body/tab", "follow").toUInt32();
    sal_uInt32 nTable2 = getXPath(pXmlDoc, "//page[2]//body/tab", "id").toUInt32();
    sal_uInt32 nTable2Precede = getXPath(pXmlDoc, "//page[2]//body/tab", "precede").toUInt32();
    sal_uInt32 nTable2Follow = getXPath(pXmlDoc, "//page[2]//body/tab", "follow").toUInt32();
    sal_uInt32 nTable3 = getXPath(pXmlDoc, "//page[3]//body/tab", "id").toUInt32();
    sal_uInt32 nTable3Precede = getXPath(pXmlDoc, "//page[3]//body/tab", "precede").toUInt32();

    // Make sure the outer table frames are linked together properly.
    CPPUNIT_ASSERT_EQUAL(nTable2, nTable1Follow);
    CPPUNIT_ASSERT_EQUAL(nTable1, nTable2Precede);
    CPPUNIT_ASSERT_EQUAL(nTable3, nTable2Follow);
    CPPUNIT_ASSERT_EQUAL(nTable2, nTable3Precede);
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testSectionInTableInTable4)
{
#if HAVE_MORE_FONTS
    createSwDoc("tdf113520.fodt");
    SwDoc* pDoc = getSwDoc();
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "/root/page", 3);
    SwNodeOffset nPage1LastNode(
        getXPath(pXmlDoc, "/root/page[1]/body/tab/row/cell[1]/tab/row/cell[1]/section/txt[last()]",
                 "txtNodeIndex")
            .toUInt32());
    CPPUNIT_ASSERT_EQUAL(u"Section1:P10"_ustr,
                         pDoc->GetNodes()[nPage1LastNode]->GetTextNode()->GetText());
    SwNodeOffset nPage3FirstNode(
        getXPath(pXmlDoc, "/root/page[3]/body/tab/row/cell[1]/tab/row/cell[1]/section/txt[1]",
                 "txtNodeIndex")
            .toUInt32());
    CPPUNIT_ASSERT_EQUAL(u"Section1:P23"_ustr,
                         pDoc->GetNodes()[nPage3FirstNode]->GetTextNode()->GetText());

    // Remove page 2.
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    while (pWrtShell->GetCursor()->Start()->GetNodeIndex() < nPage1LastNode)
        pWrtShell->Down(/*bSelect=*/false);
    pWrtShell->EndPara();
    while (pWrtShell->GetCursor()->End()->GetNodeIndex() < nPage3FirstNode)
        pWrtShell->Down(/*bSelect=*/true);
    pWrtShell->EndPara(/*bSelect=*/true);
    pWrtShell->DelLeft();

    // Assert that the page is removed.
    pXmlDoc = parseLayoutDump();
    // This was 3, page 2 was emptied, but it wasn't removed.
    assertXPath(pXmlDoc, "/root/page", 2);

    // Make sure the outer table frames are linked together properly.
    sal_uInt32 nTable1 = getXPath(pXmlDoc, "//page[1]//body/tab", "id").toUInt32();
    sal_uInt32 nTable1Follow = getXPath(pXmlDoc, "//page[1]//body/tab", "follow").toUInt32();
    sal_uInt32 nTable2 = getXPath(pXmlDoc, "//page[2]//body/tab", "id").toUInt32();
    sal_uInt32 nTable2Precede = getXPath(pXmlDoc, "//page[2]//body/tab", "precede").toUInt32();
    CPPUNIT_ASSERT_EQUAL(nTable2, nTable1Follow);
    CPPUNIT_ASSERT_EQUAL(nTable1, nTable2Precede);
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112160)
{
#if HAVE_MORE_FONTS
    // Assert that the A2 cell is on page 1.
    createSwDoc("tdf112160.fodt");
    SwDoc* pDoc = getSwDoc();
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    SwNodeOffset nA2CellNode(getXPath(pXmlDoc,
                                      "/root/page[1]/body/tab/row[2]/cell[1]/section/txt[last()]",
                                      "txtNodeIndex")
                                 .toUInt32());
    CPPUNIT_ASSERT_EQUAL(u"Table1.A2"_ustr,
                         pDoc->GetNodes()[nA2CellNode]->GetTextNode()->GetText());

    // Append a new paragraph to the end of the A2 cell.
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    while (pWrtShell->GetCursor()->GetPointNode().GetIndex() < nA2CellNode)
        pWrtShell->Down(/*bSelect=*/false);
    pWrtShell->EndPara();
    pWrtShell->SplitNode();

    // Assert that after A2 got extended, D2 stays on page 1.
    pXmlDoc = parseLayoutDump();
    sal_uInt32 nD2CellNode
        = getXPath(pXmlDoc, "/root/page[1]/body/tab/row[2]/cell[last()]/section/txt[last()]",
                   "txtNodeIndex")
              .toUInt32();
    // This was Table1.C2, Table1.D2 was moved to the next page, unexpected.
    CPPUNIT_ASSERT_EQUAL(u"Table1.D2"_ustr,
                         pDoc->GetNodes()[SwNodeOffset(nD2CellNode)]->GetTextNode()->GetText());
#endif
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf114536)
{
    // This crashed in SwTextFormatter::MergeCharacterBorder() due to a
    // use after free.
    createSwDoc("tdf114536.odt");
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testParagraphOfTextRange)
{
    createSwDoc("paragraph-of-text-range.odt");

    // Enter the table.
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->Down(/*bSelect=*/false);
    CPPUNIT_ASSERT(pWrtShell->IsCursorInTable());
    // Enter the section.
    pWrtShell->Down(/*bSelect=*/false);
    CPPUNIT_ASSERT(pWrtShell->IsDirectlyInSection());

    // Assert that we get the right paragraph object.
    uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
    uno::Reference<text::XTextViewCursorSupplier> xController(xModel->getCurrentController(),
                                                              uno::UNO_QUERY);
    uno::Reference<text::XTextRange> xViewCursor = xController->getViewCursor();
    // This failed as there were no TextParagraph property.
    auto xParagraph = getProperty<uno::Reference<text::XTextRange>>(xViewCursor->getStart(),
                                                                    u"TextParagraph"_ustr);
    CPPUNIT_ASSERT_EQUAL(u"In section"_ustr, xParagraph->getString());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf99689TableOfContents)
{
    createSwDoc("tdf99689.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->GotoNextTOXBase();
    const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
    pWrtShell->UpdateTableOf(*pTOXBase);
    SwCursorShell* pShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT(pShell);
    SwTextNode* pTitleNode = pShell->GetCursor()->GetPointNode().GetTextNode();
    SwNodeIndex aIdx(*pTitleNode);
    // skip the title
    SwNodes::GoNext(&aIdx);

    // skip the first header. No attributes there.
    // next node should contain superscript
    SwTextNode* pNext = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
    CPPUNIT_ASSERT(pNext->HasHints());
    sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);

    // next node should contain subscript
    pNext = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
    CPPUNIT_ASSERT(pNext->HasHints());
    nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf99689TableOfFigures)
{
    createSwDoc("tdf99689_figures.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->GotoNextTOXBase();
    const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
    pWrtShell->UpdateTableOf(*pTOXBase);
    SwCursorShell* pShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT(pShell);
    SwTextNode* pTitleNode = pShell->GetCursor()->GetPointNode().GetTextNode();
    SwNodeIndex aIdx(*pTitleNode);

    // skip the title
    // next node should contain subscript
    SwTextNode* pNext = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
    CPPUNIT_ASSERT(pNext->HasHints());
    sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);

    // next node should contain superscript
    pNext = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
    CPPUNIT_ASSERT(pNext->HasHints());
    nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf99689TableOfTables)
{
    createSwDoc("tdf99689_tables.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    pWrtShell->GotoNextTOXBase();
    const SwTOXBase* pTOXBase = pWrtShell->GetCurTOX();
    pWrtShell->UpdateTableOf(*pTOXBase);
    SwCursorShell* pShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT(pShell);
    SwTextNode* pTitleNode = pShell->GetCursor()->GetPointNode().GetTextNode();
    SwNodeIndex aIdx(*pTitleNode);

    // skip the title
    // next node should contain superscript
    SwTextNode* pNext = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
    CPPUNIT_ASSERT(pNext->HasHints());
    sal_uInt16 nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);

    // next node should contain subscript
    pNext = static_cast<SwTextNode*>(SwNodes::GoNext(&aIdx));
    CPPUNIT_ASSERT(pNext->HasHints());
    nAttrType = lcl_getAttributeIDFromHints(pNext->GetSwpHints());
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(RES_CHRATR_ESCAPEMENT), nAttrType);
}

// tdf#112448: Fix: take correct line height
//
// When line metrics is not calculated we need to call CalcRealHeight()
// before usage of the Height() and GetRealHeight().
CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf112448)
{
    createSwDoc("tdf112448.odt");

    // check actual number of line breaks in the paragraph
    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPath(pXmlDoc, "/root/page/body/txt/SwParaPortion/SwLineLayout", 2);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113790)
{
    createSwDoc("tdf113790.docx");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    // Create the clipboard document.
    SwDoc aClipboard;
    aClipboard.SetClipBoard(true);

    // Go to fourth line - to "ABCD" bulleted list item
    pWrtShell->Down(/*bSelect=*/false, 4);
    pWrtShell->SelPara(nullptr);
    CPPUNIT_ASSERT_EQUAL(u"ABCD"_ustr, pWrtShell->GetSelText());
    pWrtShell->Copy(aClipboard);

    // Go down to next-to-last (empty) line above "Title3"
    pWrtShell->Down(/*bSelect=*/false, 4);
    pWrtShell->Paste(aClipboard);

    // Save it as DOCX & load it again
    saveAndReload(u"Office Open XML Text"_ustr);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157937)
{
    createSwDoc("tdf130088.docx");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // select paragraph
    pWrtShell->SelPara(nullptr);

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    // show changes
    CPPUNIT_ASSERT_MESSAGE(
        "redlines should be visible",
        IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));

    // cycle case with change tracking
    dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
    dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});

    // This resulted freezing
    dispatchCommand(mxComponent, u".uno:ChangeCaseRotateCase"_ustr, {});
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157988)
{
    createSwDoc("tdf130088.docx");
    SwDoc* pDoc = getSwDoc();

    // select the second word
    dispatchCommand(mxComponent, u".uno:GoToNextWord"_ustr, {});
    dispatchCommand(mxComponent, u".uno:SelectWord"_ustr, {});

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    // show changes
    CPPUNIT_ASSERT_MESSAGE(
        "redlines should be visible",
        IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));

    // cycle case with change tracking

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSodales"));

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

    // This was false (missing revert of the tracked change)
    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSodales"));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));

    // tdf#141198 cycle case without selection: the word under the cursor

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

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

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodalesSodales"));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt"));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157667)
{
    createSwDoc("tdf130088.docx");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // select the first three words
    pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 25, /*bBasicCall=*/false);

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    // show changes
    CPPUNIT_ASSERT_MESSAGE(
        "redlines should be visible",
        IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));

    // cycle case with change tracking

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
        "Integer sodalesSodales tinciduntTincidunt tristique."));

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

    // This was false (missing revert of the tracked change)
    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
        "Integer sodalesINTEGER SODALES tincidunt tristique."));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
        "Integer sodalesSodales tinciduntTincidunt tristique."));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf158039)
{
    createSwDoc("tdf130088.docx");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // select the first sentence
    pWrtShell->Right(SwCursorSkipMode::Chars, /*bSelect=*/true, 26, /*bBasicCall=*/false);

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    // show changes
    CPPUNIT_ASSERT_MESSAGE(
        "redlines should be visible",
        IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));

    // cycle case with change tracking

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
        "Integer sodalesSodales tinciduntTincidunt tristique."));

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

    // This was false (missing revert of the tracked change)
    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
        "Integer sodalesINTEGER SODALES tincidunt tristique."));

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

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith(
        "Integer sodalesSodales tinciduntTincidunt tristique."));

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

    CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf108048)
{
    createSwDoc();

    uno::Sequence<beans::PropertyValue> aPropertyValues = comphelper::InitPropertySequence({
        { "Kind", uno::Any(sal_Int16(3)) },
        { "TemplateName", uno::Any(u"Default Page Style"_ustr) },
        { "PageNumber", uno::Any(sal_uInt16(6)) }, // Even number to avoid auto-inserted blank page
        { "PageNumberFilled", uno::Any(true) },
    });
    dispatchCommand(mxComponent, u".uno:InsertBreak"_ustr, aPropertyValues);
    CPPUNIT_ASSERT_EQUAL(2, getParagraphs());
    CPPUNIT_ASSERT_EQUAL(2, getPages());

    // The inserted page must have page number set to 6
    uno::Reference<text::XTextRange> xPara = getParagraph(2);
    sal_uInt16 nPageNumber = getProperty<sal_uInt16>(xPara, u"PageNumberOffset"_ustr);
    CPPUNIT_ASSERT_EQUAL(sal_uInt16(6), nPageNumber);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf113481)
{
    createSwDoc("tdf113481-IVS.odt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();

    // One backspace should completely remove the CJK ideograph variation sequence
    pWrtShell->EndPara();
    // Before: U+8FBA U+E0102. After: empty
    pWrtShell->DelLeft();
    const uno::Reference<text::XTextRange> xPara1 = getParagraph(1);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xPara1->getString().getLength());

    // Also variation sequence of weak characters that are treated as CJK script
    pWrtShell->Down(false);
    pWrtShell->EndPara();
    // Before: U+4E2D U+2205 U+FE00. After: U+4E2D U+2205
    pWrtShell->DelLeft();
    const uno::Reference<text::XTextRange> xPara2 = getParagraph(2);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xPara2->getString().getLength());
    CPPUNIT_ASSERT_EQUAL(u'\x4E2D', xPara2->getString()[0]);

    // Also variation sequence of other scripts
    pWrtShell->Down(false);
    pWrtShell->EndPara();
    // Before: U+1820 U+180B. After: U+1820
    pWrtShell->DelLeft();
    const uno::Reference<text::XTextRange> xPara3 = getParagraph(3);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(0), xPara3->getString().getLength());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf115013)
{
    static constexpr OUString sColumnName(u"Name with spaces, \"quotes\" and \\backslashes"_ustr);

    utl::TempFileNamed aTempDir(nullptr, true);
    aTempDir.EnableKillingFile();
    const OUString aWorkDir = aTempDir.GetURL();

    //create new writer document
    createSwDoc();
    SwDoc* pDoc = getSwDoc();

    {
        // Load and register data source
        OUString sDataSource
            = SwDBManager::LoadAndRegisterDataSource(createFileURL(u"datasource.ods"), &aWorkDir);
        CPPUNIT_ASSERT(!sDataSource.isEmpty());

        // Insert a new field type for the mailmerge field
        SwDBData aDBData;
        aDBData.sDataSource = sDataSource;
        aDBData.sCommand = "Sheet1";
        SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
        CPPUNIT_ASSERT(pWrtShell);
        SwDBFieldType* pFieldType = static_cast<SwDBFieldType*>(
            pWrtShell->InsertFieldType(SwDBFieldType(pDoc, sColumnName, aDBData)));
        CPPUNIT_ASSERT(pFieldType);

        // Insert the field into document
        SwDBField aField(pFieldType);
        pWrtShell->InsertField2(aField);
    }
    // Save it as DOCX & load it again
    saveAndReload(u"Office Open XML Text"_ustr);
    pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);
    SwCursorShell* pShell(pDoc->GetEditShell());
    CPPUNIT_ASSERT(pShell);
    SwPaM* pCursor = pShell->GetCursor();
    CPPUNIT_ASSERT(pCursor);

    // Get the field at the beginning of the document
    SwDBField* pField = dynamic_cast<SwDBField*>(SwCursorShell::GetFieldAtCursor(pCursor, true));
    CPPUNIT_ASSERT(pField);
    OUString sColumn = static_cast<SwDBFieldType*>(pField->GetTyp())->GetColumnName();
    // The column name must come correct after round trip
    CPPUNIT_ASSERT_EQUAL(sColumnName, sColumn);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf115065)
{
    // In the document, the tables have table style assigned
    // Source table (first one) has two rows;
    // destination (second one) has only one row
    createSwDoc("tdf115065.odt");
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    pWrtShell->GotoTable(UIName(u"Table2"_ustr));
    SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
    // Destination point is the middle of the first cell of second table
    Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);

    pWrtShell->GotoTable(UIName(u"Table1"_ustr));
    aRect = pWrtShell->GetCurrFrame()->getFrameArea();
    // Source point is the middle of the first cell of first table
    Point ptFrom(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);

    pWrtShell->SelTableCol();
    // The copy operation (or closing document after that) segfaulted
    pWrtShell->Copy(*pWrtShell, ptFrom, ptTo);
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf84806_MovingMultipleTableRows)
{
    // Moving of multiple table rows.
    // Source table (first one) has two rows;
    // destination (second one) has only one row
    createSwDoc("tdf115065.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
                                                    uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
    uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table2"_ustr));
    uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTable2(xTableNames->getByName(u"Table2"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2->getRows()->getCount());

    // without redlining
    CPPUNIT_ASSERT_MESSAGE("redlining should be off",
                           !pDoc->getIDocumentRedlineAccess().IsRedlineOn());

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

    pWrtShell->GotoTable(UIName(u"Table2"_ustr));
    SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
    // Destination point is the middle of the first cell of second table
    Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);

    // Move rows of the first table into the second table
    pWrtShell->GotoTable(UIName(u"Table1"_ustr));
    pWrtShell->SelTable();
    rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
    xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);

    // This was 2 tables
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());

    // Undo results 2 tables
    rUndoManager.Undo();
    uno::Reference<container::XIndexAccess> xTables2(xTablesSupplier->getTextTables(),
                                                     uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables2->getCount());
    uno::Reference<text::XTextTable> xTable1b(xTableNames->getByName(u"Table1"_ustr),
                                              uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTable2b(xTableNames->getByName(u"Table2"_ustr),
                                              uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());

    // FIXME assert with Redo()
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf147181_TrackedMovingOfMultipleTableRows)
{
    // Tracked moving of multiple table rows.
    // Source table (first one) has two rows;
    // destination (second one) has only one row
    createSwDoc("tdf115065.odt");
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
                                                    uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
    uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table2"_ustr));
    uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTable2(xTableNames->getByName(u"Table2"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2->getRows()->getCount());

    // FIXME: doesn't work with empty rows, yet
    pWrtShell->Insert(u"x"_ustr);
    pWrtShell->Down(false);
    pWrtShell->Insert(u"x"_ustr);

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    // show changes
    CPPUNIT_ASSERT_MESSAGE(
        "redlines should be visible",
        IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags()));

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

    pWrtShell->GotoTable(UIName(u"Table2"_ustr));
    SwRect aRect = pWrtShell->GetCurrFrame()->getFrameArea();
    // Destination point is the middle of the first cell of second table
    Point ptTo(aRect.Left() + aRect.Width() / 2, aRect.Top() + aRect.Height() / 2);

    // Move rows of the first table into the second table
    pWrtShell->GotoTable(UIName(u"Table1"_ustr));
    pWrtShell->SelTable();
    rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
    xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);

    // still 2 tables, but the second one has got 3 rows
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());

    // accept changes results 1 table (removing moved table)
    dispatchCommand(mxComponent, u".uno:AcceptAllTrackedChanges"_ustr, {});
    uno::Reference<container::XIndexAccess> xTables2(xTablesSupplier->getTextTables(),
                                                     uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables2->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getRows()->getCount());

    // Undo results 2 tables
    rUndoManager.Undo();
    rUndoManager.Undo();
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables2->getCount());
    uno::Reference<text::XTextTable> xTable1b(xTableNames->getByName(u"Table1"_ustr),
                                              uno::UNO_QUERY);
    uno::Reference<text::XTextTable> xTable2b(xTableNames->getByName(u"Table2"_ustr),
                                              uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());

    // reject changes results 2 table again, with the original row counts
    dispatchCommand(mxComponent, u".uno:RejectAllTrackedChanges"_ustr, {});
    uno::Reference<container::XIndexAccess> xTables3(xTablesSupplier->getTextTables(),
                                                     uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTables3->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1b->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable2b->getRows()->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157492_TrackedMovingRow)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // Create a table
    SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
    (void)&pWrtShell->InsertTable(TableOpt, 4, 3);

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());

    // fill table with data
    SwXTextDocument* pTextDoc = getSwTextDoc();
    for (int i = 0; i < 3; ++i)
    {
        pWrtShell->Insert(u"x"_ustr);
        pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_RIGHT);
    }

    Scheduler::ProcessEventsToIdle();

    uno::Reference<text::XTextRange> xCellA1(xTable1->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
    xCellA1->setString(u"A1"_ustr);
    uno::Reference<text::XTextRange> xCellB1(xTable1->getCellByName(u"B1"_ustr), uno::UNO_QUERY);
    xCellB1->setString(u"B1"_ustr);
    uno::Reference<text::XTextRange> xCellC1(xTable1->getCellByName(u"C1"_ustr), uno::UNO_QUERY);
    xCellC1->setString(u"C1"_ustr);

    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[1]/txt", u"A1");
    assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[2]/txt", u"B1");
    assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[3]/txt", u"C1");

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    // Move first column of the table before the third column by drag & drop
    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
    SwFrame* pPage = pLayout->Lower();
    SwFrame* pBody = pPage->GetLower();
    SwFrame* pTable = pBody->GetLower();
    SwFrame* pRow1 = pTable->GetLower();
    SwFrame* pCellA1 = pRow1->GetLower();
    SwFrame* pRow3 = pRow1->GetNext()->GetNext();
    SwFrame* pCellA3 = pRow3->GetLower();
    const SwRect& rCellA1Rect = pCellA1->getFrameArea();
    const SwRect& rCellA3Rect = pCellA3->getFrameArea();
    Point ptTo(rCellA3Rect.Left() + rCellA3Rect.Width() / 2,
               rCellA3Rect.Top() + rCellA3Rect.Height() / 2);
    // select first table row by using the middle point of the left border of row 1
    Point ptRow(rCellA1Rect.Left() - 5, rCellA1Rect.Top() + rCellA1Rect.Height() / 2);
    pWrtShell->SelectTableRowCol(ptRow);

    rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);

    xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);

    // reject changes results 4 rows again, not 5
    dispatchCommand(mxComponent, u".uno:RejectAllTrackedChanges"_ustr, {});

    xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    uno::Reference<text::XTextTable> xTable2(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getColumns()->getCount());
    // This was 5 (moving row without change tracking)
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable2->getRows()->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf154599_MovingColumn)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // Create a table with less columns than rows
    SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
    (void)&pWrtShell->InsertTable(TableOpt, 4, 3);

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());

    // without redlining
    CPPUNIT_ASSERT_MESSAGE("redlining should be off",
                           !pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    // Move first column of the table before the third column by drag & drop

    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
    SwFrame* pPage = pLayout->Lower();
    SwFrame* pBody = pPage->GetLower();
    SwFrame* pTable = pBody->GetLower();
    SwFrame* pRow1 = pTable->GetLower();
    SwFrame* pCellA1 = pRow1->GetLower();
    SwFrame* pCellC1 = pCellA1->GetNext()->GetNext();
    const SwRect& rCellA1Rect = pCellA1->getFrameArea();
    const SwRect& rCellC1Rect = pCellC1->getFrameArea();
    Point ptTo(rCellC1Rect.Left() + rCellC1Rect.Width() / 2,
               rCellC1Rect.Top() + rCellC1Rect.Height() / 2);
    // select first table column by using the middle point of the top border of column A
    Point ptColumn(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() - 5);
    pWrtShell->SelectTableRowCol(ptColumn);

    // This crashed here before the fix.
    rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);

    xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf155846_MovingColumn)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // Create a table
    SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
    (void)&pWrtShell->InsertTable(TableOpt, 4, 3);

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount());

    // fill table with data
    SwXTextDocument* pTextDoc = getSwTextDoc();
    for (int i = 0; i < 4; ++i)
    {
        pWrtShell->Insert(u"x"_ustr);
        pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, 0, KEY_DOWN);
    }

    Scheduler::ProcessEventsToIdle();

    uno::Reference<text::XTextRange> xCellA1(xTable1->getCellByName(u"A1"_ustr), uno::UNO_QUERY);
    xCellA1->setString(u"A1"_ustr);
    uno::Reference<text::XTextRange> xCellA2(xTable1->getCellByName(u"A2"_ustr), uno::UNO_QUERY);
    xCellA2->setString(u"A2"_ustr);
    uno::Reference<text::XTextRange> xCellA3(xTable1->getCellByName(u"A3"_ustr), uno::UNO_QUERY);
    xCellA3->setString(u"A3"_ustr);
    uno::Reference<text::XTextRange> xCellA4(xTable1->getCellByName(u"A4"_ustr), uno::UNO_QUERY);
    xCellA4->setString(u"A4"_ustr);

    xmlDocUniquePtr pXmlDoc = parseLayoutDump();
    assertXPathContent(pXmlDoc, "/root/page/body/tab/row[1]/cell[1]/txt", u"A1");
    assertXPathContent(pXmlDoc, "/root/page/body/tab/row[2]/cell[1]/txt", u"A2");
    assertXPathContent(pXmlDoc, "/root/page/body/tab/row[3]/cell[1]/txt", u"A3");
    assertXPathContent(pXmlDoc, "/root/page/body/tab/row[4]/cell[1]/txt", u"A4");

    // enable redlining
    dispatchCommand(mxComponent, u".uno:TrackChanges"_ustr, {});
    CPPUNIT_ASSERT_MESSAGE("redlining should be on",
                           pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    // Move first column of the table before the third column by drag & drop
    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
    SwFrame* pPage = pLayout->Lower();
    SwFrame* pBody = pPage->GetLower();
    SwFrame* pTable = pBody->GetLower();
    SwFrame* pRow1 = pTable->GetLower();
    SwFrame* pCellA1 = pRow1->GetLower();
    SwFrame* pCellC1 = pCellA1->GetNext()->GetNext();
    const SwRect& rCellA1Rect = pCellA1->getFrameArea();
    const SwRect& rCellC1Rect = pCellC1->getFrameArea();
    Point ptTo(rCellC1Rect.Left() + rCellC1Rect.Width() / 2,
               rCellC1Rect.Top() + rCellC1Rect.Height() / 2);
    // select first table column by using the middle point of the top border of column A
    Point ptColumn(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() - 5);
    pWrtShell->SelectTableRowCol(ptColumn);

    // This crashed here before the fix.
    rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);

    xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);

    // reject changes results 3 columns again, not 4
    dispatchCommand(mxComponent, u".uno:RejectAllTrackedChanges"_ustr, {});

    xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    uno::Reference<text::XTextTable> xTable2(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable2->getRows()->getCount());
    // This was 4 (moving column without change tracking)
    CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable2->getColumns()->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf154771_MovingMultipleColumns)
{
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // Create a table with less columns than rows
    SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
    (void)&pWrtShell->InsertTable(TableOpt, 5, 4);

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getColumns()->getCount());

    // without redlining
    CPPUNIT_ASSERT_MESSAGE("redlining should be off",
                           !pDoc->getIDocumentRedlineAccess().IsRedlineOn());

    // Move first two columns of the table before column D by drag & drop

    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
    SwFrame* pPage = pLayout->Lower();
    SwFrame* pBody = pPage->GetLower();
    SwFrame* pTable = pBody->GetLower();
    SwFrame* pRow1 = pTable->GetLower();
    SwFrame* pCellA1 = pRow1->GetLower();
    SwFrame* pCellB1 = pCellA1->GetNext();
    SwFrame* pCellD1 = pCellB1->GetNext()->GetNext();
    const SwRect& rCellA1Rect = pCellA1->getFrameArea();
    const SwRect& rCellB1Rect = pCellB1->getFrameArea();
    const SwRect& rCellD1Rect = pCellD1->getFrameArea();
    Point ptTo(rCellD1Rect.Left() + rCellD1Rect.Width() / 2,
               rCellD1Rect.Top() + rCellD1Rect.Height() / 2);
    // select first two table columns by using
    // the middle point of the top border of column A
    // and middle point of the top border of column B
    Point ptColumnA(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() - 5);
    const Point ptColumnB(rCellB1Rect.Left() + rCellB1Rect.Width() / 2, rCellB1Rect.Top() - 5);
    pWrtShell->SelectTableRowCol(ptColumnA, &ptColumnB);

    rtl::Reference<SwTransferable> xTransfer = new SwTransferable(*pWrtShell);
    xTransfer->PrivateDrop(*pWrtShell, ptTo, /*bMove=*/true, /*bXSelection=*/true);

    CPPUNIT_ASSERT_EQUAL(sal_Int32(5), xTable1->getRows()->getCount());
    // This was 5 before the fix (only the first selected column was moved, the
    // other ones were copied instead of moving)
    CPPUNIT_ASSERT_EQUAL(sal_Int32(4), xTable1->getColumns()->getCount());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf44773)
{
    // allow resizing table rows, if cursor outside the table
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // insert an empty paragraph
    pWrtShell->SplitNode();

    // create a table
    SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
    (void)&pWrtShell->InsertTable(TableOpt, 2, 1);

    // the cursor is not inside the table
    CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable1->getColumns()->getCount());

    Scheduler::ProcessEventsToIdle();

    // set table row height by drag & drop
    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();

    SwFrame* pPage = pLayout->Lower();
    SwFrame* pBody = pPage->GetLower();
    SwFrame* pTable = pBody->GetLower()->GetNext();
    SwFrame* pRow1 = pTable->GetLower();
    CPPUNIT_ASSERT(pRow1->IsRowFrame());
    SwFrame* pCellA1 = pRow1->GetLower();
    const SwRect& rCellA1Rect = pCellA1->getFrameArea();
    auto nRowHeight = rCellA1Rect.Height();
    // select center of the bottom border of the first table cell
    Point ptFrom(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + nRowHeight);
    // double the row height
    Point ptTo(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + 2 * nRowHeight);
    vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
    Point aFrom = rEditWin.LogicToPixel(ptFrom);
    MouseEvent aClickEvent(aFrom, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
                           MOUSE_LEFT);
    rEditWin.MouseButtonDown(aClickEvent);
    Point aTo = rEditWin.LogicToPixel(ptTo);
    MouseEvent aMoveEvent(aTo, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
                          MOUSE_LEFT);
    TrackingEvent aTEvt(aMoveEvent, TrackingEventFlags::Repeat);
    // drag & drop of cell border inside the document (and outside the table)
    // still based on the ruler code, use that to simulate dragging
    getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt);
    TrackingEvent aTEvt2(aMoveEvent, TrackingEventFlags::End);
    getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt2);
    Scheduler::ProcessEventsToIdle();
    rEditWin.CaptureMouse();
    rEditWin.ReleaseMouse();

    // this was 396 (not modified row height previously)
    CPPUNIT_ASSERT_GREATER(tools::Long(750), pCellA1->getFrameArea().Height());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf157833)
{
    // allow resizing table rows & columns using a minimal hit area
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // insert an empty paragraph
    pWrtShell->SplitNode();

    // create a table
    SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
    (void)&pWrtShell->InsertTable(TableOpt, 2, 1);

    // the cursor is not inside the table
    CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable1->getColumns()->getCount());

    Scheduler::ProcessEventsToIdle();

    // set table row height by drag & drop
    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();

    SwFrame* pPage = pLayout->Lower();
    SwFrame* pBody = pPage->GetLower();
    SwFrame* pTable = pBody->GetLower()->GetNext();
    SwFrame* pRow1 = pTable->GetLower();
    CPPUNIT_ASSERT(pRow1->IsRowFrame());
    SwFrame* pCellA1 = pRow1->GetLower();
    const SwRect& rCellA1Rect = pCellA1->getFrameArea();
    auto nRowHeight = rCellA1Rect.Height();
    // select center of the bottom border of the first table cell
    Point ptFrom(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + nRowHeight);
    // double the row height
    Point ptTo(rCellA1Rect.Left() + rCellA1Rect.Width() / 2, rCellA1Rect.Top() + 2 * nRowHeight);
    vcl::Window& rEditWin = getSwDocShell()->GetView()->GetEditWin();
    Point aFrom = rEditWin.LogicToPixel(ptFrom);
    Point aArea(aFrom.X(), aFrom.Y() + 2);
    MouseEvent aClickEvent(aArea, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
                           MOUSE_LEFT);
    rEditWin.MouseButtonDown(aClickEvent);
    Point aTo = rEditWin.LogicToPixel(ptTo);
    MouseEvent aMoveEvent(aTo, 1, MouseEventModifiers::SIMPLECLICK | MouseEventModifiers::SELECT,
                          MOUSE_LEFT);
    TrackingEvent aTEvt(aMoveEvent, TrackingEventFlags::Repeat);
    // drag & drop of cell border inside the document (and outside the table)
    // still based on the ruler code, use that to simulate dragging
    getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt);
    TrackingEvent aTEvt2(aMoveEvent, TrackingEventFlags::End);
    getSwDocShell()->GetView()->GetVRuler().Tracking(aTEvt2);
    Scheduler::ProcessEventsToIdle();
    rEditWin.CaptureMouse();
    rEditWin.ReleaseMouse();

    // this was 396 (not modified row height previously, when clicking only in a 2-pixel distance
    // from the center of the border)
    CPPUNIT_ASSERT_GREATER(tools::Long(750), pCellA1->getFrameArea().Height());
}

CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf155692)
{
    // allow resizing table rows & columns using a normal hit area
    createSwDoc();
    SwDoc* pDoc = getSwDoc();
    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
    CPPUNIT_ASSERT(pWrtShell);

    // insert an empty paragraph
    pWrtShell->SplitNode();

    // create a table
    SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
    (void)&pWrtShell->InsertTable(TableOpt, 2, 1);

    // the cursor is not inside the table
    CPPUNIT_ASSERT(!pWrtShell->IsCursorInTable());

    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XNameAccess> xTableNames = xTablesSupplier->getTextTables();
    CPPUNIT_ASSERT(xTableNames->hasByName(u"Table1"_ustr));
    uno::Reference<text::XTextTable> xTable1(xTableNames->getByName(u"Table1"_ustr),
                                             uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int32(2), xTable1->getRows()->getCount());
    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTable1->getColumns()->getCount());

    Scheduler::ProcessEventsToIdle();

    // set table row height by drag & drop
--> --------------------

--> maximum size reached

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

Messung V0.5
C=90 H=94 G=91

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