sw/qa/extras/uiwriter/uiwriter6.cxx  |   56 ++++++++++++++++++++++++++++++
 sw/source/uibase/dochdl/swdtflvr.cxx |   64 ++++++++++++++++++++++++-----------
 2 files changed, 100 insertions(+), 20 deletions(-)

New commits:
commit 1bf651f34b1e3abb5cbaf6b810aa0b0d9ee86368
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Wed Apr 12 13:27:25 2023 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Wed Apr 12 19:08:06 2023 +0200

    tdf#154771 sw: fix drag & drop moving of table columns
    
    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 <nem...@numbertext.org>
    (cherry picked from commit 49f80aedf3f2dff70aa410319e80e8622dfa31a1)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150207
    Tested-by: László Németh <nem...@numbertext.org>

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<text::XTextTablesSupplier> xTablesSupplier(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> 
xTables(xTablesSupplier->getTextTables(),
+                                                    uno::UNO_QUERY);
+    uno::Reference<container::XNameAccess> xTableNames = 
xTablesSupplier->getTextTables();
+    CPPUNIT_ASSERT(xTableNames->hasByName("Table1"));
+    uno::Reference<text::XTextTable> 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<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, 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<SwTableLine*>( 
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<SwTableLine*>(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;
                         }
                     }
                 }

Reply via email to