/* -*- 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/.
*/
class SwUiWriterTest6 : public SwModelTestBase, public HtmlTestTools
{ public:
SwUiWriterTest6()
: SwModelTestBase(u"/sw/qa/extras/uiwriter/data/"_ustr)
{
}
};
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());
// 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
}
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
}
// 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
}
// 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
}
// 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);
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");
}
// 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());
}
// 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);
}
// 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);
}
// 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);
}
// 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, {});
}
// 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()));
// 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()));
// This was false (missing revert of the tracked change)
CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));
// 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()));
// This was false (missing revert of the tracked change)
CPPUNIT_ASSERT(getParagraph(1)->getString().startsWith("Integer sodales tincidunt tristique."));
// 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);
}
//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);
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());
// 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()));
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());
// 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);
}
// 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);
// Create a table with less columns than rows
SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
(void)&pWrtShell->InsertTable(TableOpt, 4, 3);
// 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);
}
// 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);
// Create a table with less columns than rows
SwInsertTableOptions TableOpt(SwInsertTableFlags::DefaultBorder, 0);
(void)&pWrtShell->InsertTable(TableOpt, 5, 4);
// 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());
}
// 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());
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.