From 1bf651f34b1e3abb5cbaf6b810aa0b0d9ee86368 Mon Sep 17 00:00:00 2001 From: László Németh Date: Wed, 12 Apr 2023 13:27:25 +0200 Subject: tdf#154771 sw: fix drag & drop moving of table columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only first selected column was moved, the other ones were copied during drag & drop moving of table columns. Regression from commit 5e8aa259e48d5602b932353bb146ebb523982cf2 "tdf#146967 sw table: fix freezing in Hide Changes mode". Follow-up to commit 912336f3c85d9a631fa0ac0f270bab04b204f619 "tdf#154599 sw: fix crash at drag & drop table columns". Change-Id: I31ca5b3d6004ed53c11a951fa184b9db48f21041 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150280 Tested-by: Jenkins Reviewed-by: László Németh (cherry picked from commit 49f80aedf3f2dff70aa410319e80e8622dfa31a1) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150207 Tested-by: László Németh --- sw/qa/extras/uiwriter/uiwriter6.cxx | 56 +++++++++++++++++++++++++++++++ sw/source/uibase/dochdl/swdtflvr.cxx | 64 +++++++++++++++++++++++++----------- 2 files changed, 100 insertions(+), 20 deletions(-) diff --git a/sw/qa/extras/uiwriter/uiwriter6.cxx b/sw/qa/extras/uiwriter/uiwriter6.cxx index eeae8a5387d4..c1fe8f97984a 100644 --- a/sw/qa/extras/uiwriter/uiwriter6.cxx +++ b/sw/qa/extras/uiwriter/uiwriter6.cxx @@ -992,6 +992,62 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf154599_MovingColumn) CPPUNIT_ASSERT_EQUAL(sal_Int32(3), xTable1->getColumns()->getCount()); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest6, testTdf154771_MovingMultipleColumns) +{ + createSwDoc(); + SwDoc* pDoc = getSwDoc(); + CPPUNIT_ASSERT(pDoc); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->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 xTablesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference xTables(xTablesSupplier->getTextTables(), + uno::UNO_QUERY); + uno::Reference xTableNames = xTablesSupplier->getTextTables(); + CPPUNIT_ASSERT(xTableNames->hasByName("Table1")); + uno::Reference xTable1(xTableNames->getByName("Table1"), 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 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, testTdf115132) { createSwDoc(); diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx index 57615aa40a7e..ee8bec1e1060 100644 --- a/sw/source/uibase/dochdl/swdtflvr.cxx +++ b/sw/source/uibase/dochdl/swdtflvr.cxx @@ -3978,10 +3978,37 @@ bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt, // up to down, if the cursor is there in its last table row const SwSelBoxes& rBoxes = rSrcSh.GetTableCursor()->GetSelectedBoxes(); const SwTableNode* pTableNd = rSh.IsCursorInTable(); - sal_Int32 nSelRows = !rBoxes.back() - ? 0 - : pTableNd->GetTable().GetTabLines().GetPos( rBoxes.back()->GetUpper() ) - - pTableNd->GetTable().GetTabLines().GetPos( rBoxes.front()->GetUpper() ) + 1; + const SwTableLines& rLines = pTableNd->GetTable().GetTabLines(); + const SwStartNode& rDelPos = rBoxes.back() + ? *rBoxes.front()->GetSttNd() + : *pTableNd->GetStartNode(); + + // count selected rows or columns + sal_Int32 nSelRowOrCols = 0; + if ( rBoxes.back() ) + { + if ( bTableCol ) + { + // selected column count is the count of the cells + // in the first row of the selection + auto nLine = rLines.GetPos( rBoxes.front()->GetUpper() ); + for (auto pBox : rBoxes) + { + // cell is in the next row + if ( nLine != rLines.GetPos( pBox->GetUpper() ) ) + break; + ++nSelRowOrCols; + } + } + else + { + // selected row count is the difference of the row number of the + // first and the last cell of the selection + nSelRowOrCols = rLines.GetPos( rBoxes.back()->GetUpper() ) - + rLines.GetPos( rBoxes.front()->GetUpper() ) + 1; + } + } + bool bSelUpToDown = rBoxes.back() && rBoxes.back()->GetUpper() == rSh.GetCursor()->GetPointNode().GetTableBox()->GetUpper(); @@ -4038,7 +4065,7 @@ bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt, const SwTableBox* pBoxStt = rSh.GetCursor()->GetPointNode().GetTableBox(); SwTableLine* pLine = pBoxStt ? const_cast( pBoxStt->GetUpper()): nullptr; - for (sal_Int32 nDeleted = 0; bNeedTrack && nDeleted < nSelRows;) + for (sal_Int32 nDeleted = 0; bNeedTrack && nDeleted < nSelRowOrCols;) { // move up text cursor (note: "true" is important for the layout level) if ( !rSh.Up(false) ) @@ -4072,12 +4099,14 @@ bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt, rSh.getIDocumentMarkAccess()->deleteMark( pMarkMoveFrom ); } - // set all row as tracked deletion, otherwise go to the first moved row - if ( bNeedTrack || ( bSelUpToDown && nSelRows > 1 ) ) + // tracked table row moving: set original rows as tracked deletion, + // otherwise delete original rows/columns (tracking column deletion + // and insertion is not supported yet) + if ( !bTableCol && bNeedTrack ) { pLine = nullptr; - for (sal_Int32 nDeleted = 0; nDeleted < nSelRows - int(!bNeedTrack);) + for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols;) { const SwTableBox* pBox = rSh.GetCursor()->GetPointNode().GetTableBox(); @@ -4087,10 +4116,7 @@ bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt, if ( pBox->GetUpper() != pLine ) { pLine = const_cast(pBox->GetUpper()); - if (bNeedTrack) - pDispatch->Execute(bTableCol - ? FN_TABLE_DELETE_COL - : FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON); + pDispatch->Execute(FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON); ++nDeleted; } @@ -4103,19 +4129,17 @@ bool SwTransferable::PrivateDrop( SwWrtShell& rSh, const Point& rDragPt, break; } } - - // delete original rows/columns, except in track changes mode - // TODO remove all the columns, not only the first one - if ( !bNeedTrack ) + else { - for (sal_Int32 nDeleted = 0; nDeleted < nSelRows; ++nDeleted) + // set cursor in the first cell of the original selection + rSh.GetCursor()->DeleteMark(); + rSh.GetCursor()->GetPoint()->Assign( rDelPos.GetIndex() + 1); + + for (sal_Int32 nDeleted = 0; nDeleted < nSelRowOrCols; ++nDeleted) { pDispatch->Execute(bTableCol ? FN_TABLE_DELETE_COL : FN_TABLE_DELETE_ROW, SfxCallMode::SYNCHRON); - - if ( bTableCol ) - break; } } } -- cgit