summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.co.uk>2016-04-25 10:57:49 +0200
committerMiklos Vajna <vmiklos@collabora.co.uk>2016-04-25 09:52:54 +0000
commitcafc53f8b4c08443524b1da6f4918d49afd45bb5 (patch)
tree22fe5b1c721bb4a83504b89201e34e3ab77a3842
parent474eca1f9b42749665bbf69f6dc62c66ea4ad7fd (diff)
tdf#99452 svx: fix undo of table row edge drag
The problem as seen by the user: if you have a table of 2 rows and 1 column, and the separator line is dragged upwards by the mouse, then undo doesn't restore the original situation. Two items are created on the undo stack: sd::UndoGeoObject and sdr::table::TableRowUndo. Let's say the table height is 8000 mm100 and the two cell heights are 4000 and 4000. If the user resizes the first cell, so that its height is 2000, then the new table height will be 6000. The problem is that when undo is executed, first sd::UndoGeoObject resizes the table, distributing the newly available 2000 between the existing rows, and then sdr::table::TableRowUndo sets the row height of the first row: the height of the second cell will be larger than expected. Fix the problem by not doing a relayout during sd::UndoGeoObject, but doing a relayout after sdr::table::TableRowUndo in this case. This is done by: 1) Adding a new SdrDragStat::mbEndDragChangesLayout, so that SdrTableObj::applySpecialDrag() can inform SdrDragObjOwn::EndSdrDrag() that TableRowUndo will do the layout instead of UndoGeoObject. (This is done only in case a row edge is dragged, as otherwise it's not guaranteed that a TableRowUndo will follow the UndoGeoObject on the undo stack.) 2) Adding a new SdrUndoGeoObj::mbSkipChangeLayout, so that SdrTableObj::applySpecialDrag() can let SdrUndoGeoObj::Undo() not do the layout. 3) Adding a sdr::table::SdrTableObjImpl::mbSkipChangeLayout, so that SdrUndoGeoObj::Undo() can let SdrTableObj::NbcSetLogicRect() not do the layout. 4) Marking the table model as modified in TableRowUndo::setData(), so it does the layout at the end of the undo group. Change-Id: I8adde3cdad5741e6fcb420e333ce336e18c77cf1 Reviewed-on: https://gerrit.libreoffice.org/24363 Reviewed-by: Miklos Vajna <vmiklos@collabora.co.uk> Tested-by: Jenkins <ci@libreoffice.org>
-rw-r--r--include/svx/svddrag.hxx4
-rw-r--r--include/svx/svdotable.hxx3
-rw-r--r--include/svx/svdundo.hxx3
-rw-r--r--sd/qa/unit/tiledrendering/data/table.odpbin0 -> 10559 bytes
-rw-r--r--sd/qa/unit/tiledrendering/tiledrendering.cxx51
-rw-r--r--svx/source/svdraw/svddrag.cxx1
-rw-r--r--svx/source/svdraw/svddrgmt.cxx6
-rw-r--r--svx/source/svdraw/svdundo.cxx7
-rw-r--r--svx/source/table/svdotable.cxx14
-rw-r--r--svx/source/table/tablerow.cxx4
-rw-r--r--svx/source/table/tablerow.hxx2
-rw-r--r--svx/source/table/tableundo.cxx3
12 files changed, 97 insertions, 1 deletions
diff --git a/include/svx/svddrag.hxx b/include/svx/svddrag.hxx
index 0160f8040235..ef48ccf692fa 100644
--- a/include/svx/svddrag.hxx
+++ b/include/svx/svddrag.hxx
@@ -55,6 +55,8 @@ protected:
bool bEndDragChangesAttributes;
bool bEndDragChangesGeoAndAttributes;
+ /// Table row drag: table will re-layout itself later.
+ bool mbEndDragChangesLayout;
bool bMouseIsUp;
bool bShown; // Xor visible?
@@ -133,6 +135,8 @@ public:
void SetEndDragChangesAttributes(bool bOn) { bEndDragChangesAttributes=bOn; }
bool IsEndDragChangesGeoAndAttributes() const { return bEndDragChangesGeoAndAttributes; }
void SetEndDragChangesGeoAndAttributes(bool bOn) { bEndDragChangesGeoAndAttributes=bOn; }
+ bool IsEndDragChangesLayout() const { return mbEndDragChangesLayout; }
+ void SetEndDragChangesLayout(bool bOn) { mbEndDragChangesLayout=bOn; }
// Is set by the view and can be evaluated by Obj
bool IsMouseDown() const { return !bMouseIsUp; }
diff --git a/include/svx/svdotable.hxx b/include/svx/svdotable.hxx
index ed1264d5eeb9..5747e2bf3dde 100644
--- a/include/svx/svdotable.hxx
+++ b/include/svx/svdotable.hxx
@@ -253,6 +253,9 @@ public:
/// Add an undo action that should be on the undo stack after ending text edit.
void AddUndo(SdrUndoAction* pUndo);
+ /// Next time layouting would be done, skip it (to layout at the end of multiple actions).
+ void SetSkipChangeLayout(bool bSkipChangeLayout);
+
virtual void onEditOutlinerStatusEvent( EditStatus* pEditStatus ) override;
// Transformation interface for StarOfficeAPI. This implements support for
diff --git a/include/svx/svdundo.hxx b/include/svx/svdundo.hxx
index 23e65c69fd2f..5f3ee5f1601d 100644
--- a/include/svx/svdundo.hxx
+++ b/include/svx/svdundo.hxx
@@ -213,6 +213,8 @@ protected:
SdrObjGeoData* pRedoGeo;
// If we have a group object:
SdrUndoGroup* pUndoGroup;
+ /// If we have a table object, should its layout change?
+ bool mbSkipChangeLayout;
public:
SdrUndoGeoObj(SdrObject& rNewObj);
@@ -222,6 +224,7 @@ public:
virtual void Redo() override;
virtual OUString GetComment() const override;
+ void SetSkipChangeLayout(bool bOn) { mbSkipChangeLayout=bOn; }
};
/**
diff --git a/sd/qa/unit/tiledrendering/data/table.odp b/sd/qa/unit/tiledrendering/data/table.odp
new file mode 100644
index 000000000000..6d92898a00c6
--- /dev/null
+++ b/sd/qa/unit/tiledrendering/data/table.odp
Binary files differ
diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx
index 88b437f3286b..a47f99077267 100644
--- a/sd/qa/unit/tiledrendering/tiledrendering.cxx
+++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx
@@ -25,6 +25,7 @@
#include <sfx2/viewfrm.hxx>
#include <svl/srchitem.hxx>
#include <comphelper/lok.hxx>
+#include <svx/svdotable.hxx>
#include <DrawDocShell.hxx>
#include <ViewShell.hxx>
@@ -61,6 +62,7 @@ public:
void testInsertDeletePage();
void testInsertTable();
void testPartHash();
+ void testResizeTable();
#endif
CPPUNIT_TEST_SUITE(SdTiledRenderingTest);
@@ -80,6 +82,7 @@ public:
CPPUNIT_TEST(testInsertDeletePage);
CPPUNIT_TEST(testInsertTable);
CPPUNIT_TEST(testPartHash);
+ CPPUNIT_TEST(testResizeTable);
#endif
CPPUNIT_TEST_SUITE_END();
@@ -678,6 +681,54 @@ void SdTiledRenderingTest::testPartHash()
comphelper::LibreOfficeKit::setActive(false);
}
+void SdTiledRenderingTest::testResizeTable()
+{
+ // Load the document.
+ comphelper::LibreOfficeKit::setActive();
+ SdXImpressDocument* pXImpressDocument = createDoc("table.odp");
+ sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell();
+ SdPage* pActualPage = pViewShell->GetActualPage();
+ SdrObject* pObject = pActualPage->GetObj(0);
+ auto pTableObject = dynamic_cast<sdr::table::SdrTableObj*>(pObject);
+ CPPUNIT_ASSERT(pTableObject);
+
+ // Select the table by marking it + starting and ending text edit.
+ SdrView* pView = pViewShell->GetView();
+ pView->MarkObj(pObject, pView->GetSdrPageView());
+ pView->SdrBeginTextEdit(pObject);
+ pView->SdrEndTextEdit();
+
+ // Remember the original row heights.
+ uno::Reference<table::XColumnRowRange> xTable(pTableObject->getTable(), uno::UNO_QUERY);
+ uno::Reference<container::XIndexAccess> xRows(xTable->getRows(), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xRow1(xRows->getByIndex(0), uno::UNO_QUERY);
+ sal_Int32 nExpectedRow1 = xRow1->getPropertyValue("Size").get<sal_Int32>();
+ uno::Reference<beans::XPropertySet> xRow2(xRows->getByIndex(1), uno::UNO_QUERY);
+ sal_Int32 nExpectedRow2 = xRow2->getPropertyValue("Size").get<sal_Int32>();
+
+ // Resize the upper row, decrease its height by 1 cm.
+ Point aInnerRowEdge = pObject->GetSnapRect().Center();
+ pXImpressDocument->setGraphicSelection(LOK_SETGRAPHICSELECTION_START, convertMm100ToTwip(aInnerRowEdge.getX()), convertMm100ToTwip(aInnerRowEdge.getY()));
+ pXImpressDocument->setGraphicSelection(LOK_SETGRAPHICSELECTION_END, convertMm100ToTwip(aInnerRowEdge.getX()), convertMm100ToTwip(aInnerRowEdge.getY() - 1000));
+
+ // Remember the resized row heights.
+ sal_Int32 nResizedRow1 = xRow1->getPropertyValue("Size").get<sal_Int32>();
+ CPPUNIT_ASSERT(nResizedRow1 < nExpectedRow1);
+ sal_Int32 nResizedRow2 = xRow2->getPropertyValue("Size").get<sal_Int32>();
+ CPPUNIT_ASSERT_EQUAL(nExpectedRow2, nResizedRow2);
+
+ // Now undo the resize.
+ pXImpressDocument->GetDocShell()->GetUndoManager()->Undo();
+
+ // Check the undo result.
+ sal_Int32 nActualRow1 = xRow1->getPropertyValue("Size").get<sal_Int32>();
+ CPPUNIT_ASSERT_EQUAL(nExpectedRow1, nActualRow1);
+ sal_Int32 nActualRow2 = xRow2->getPropertyValue("Size").get<sal_Int32>();
+ // Expected was 4000, actual was 4572, i.e. the second row after undo was larger than expected.
+ CPPUNIT_ASSERT_EQUAL(nExpectedRow2, nActualRow2);
+ comphelper::LibreOfficeKit::setActive(false);
+}
+
#endif
CPPUNIT_TEST_SUITE_REGISTRATION(SdTiledRenderingTest);
diff --git a/svx/source/svdraw/svddrag.cxx b/svx/source/svdraw/svddrag.cxx
index 8eb54cbef3d8..75c046a1326b 100644
--- a/svx/source/svdraw/svddrag.cxx
+++ b/svx/source/svdraw/svddrag.cxx
@@ -50,6 +50,7 @@ void SdrDragStat::Reset()
pDragMethod=nullptr;
bEndDragChangesAttributes=false;
bEndDragChangesGeoAndAttributes=false;
+ mbEndDragChangesLayout=false;
bMouseIsUp=false;
Clear(true);
aActionRect=Rectangle();
diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx
index 09ca6cba9b1a..5996b50eaecd 100644
--- a/svx/source/svdraw/svddrgmt.cxx
+++ b/svx/source/svdraw/svddrgmt.cxx
@@ -1410,6 +1410,12 @@ bool SdrDragObjOwn::EndSdrDrag(bool /*bCopy*/)
}
bRet = pObj->applySpecialDrag(DragStat());
+ if (DragStat().IsEndDragChangesLayout())
+ {
+ auto pGeoUndo = dynamic_cast<SdrUndoGeoObj*>(pUndo);
+ if (pGeoUndo)
+ pGeoUndo->SetSkipChangeLayout(true);
+ }
if(bRet)
{
diff --git a/svx/source/svdraw/svdundo.cxx b/svx/source/svdraw/svdundo.cxx
index 37e81e7cdffe..e3cc47895528 100644
--- a/svx/source/svdraw/svdundo.cxx
+++ b/svx/source/svdraw/svdundo.cxx
@@ -598,6 +598,7 @@ SdrUndoGeoObj::SdrUndoGeoObj(SdrObject& rNewObj)
, pUndoGeo(nullptr)
, pRedoGeo(nullptr)
, pUndoGroup(nullptr)
+ , mbSkipChangeLayout(false)
{
SdrObjList* pOL=rNewObj.GetSubList();
if (pOL!=nullptr && pOL->GetObjCount() && dynamic_cast<const E3dScene* >( &rNewObj) == nullptr)
@@ -640,7 +641,13 @@ void SdrUndoGeoObj::Undo()
{
delete pRedoGeo;
pRedoGeo=pObj->GetGeoData();
+
+ auto pTableObj = dynamic_cast<sdr::table::SdrTableObj*>(pObj);
+ if (pTableObj && mbSkipChangeLayout)
+ pTableObj->SetSkipChangeLayout(true);
pObj->SetGeoData(*pUndoGeo);
+ if (pTableObj && mbSkipChangeLayout && pTableObj)
+ pTableObj->SetSkipChangeLayout(false);
}
}
diff --git a/svx/source/table/svdotable.cxx b/svx/source/table/svdotable.cxx
index 4121fdaf3d6c..9d13f8fca6b3 100644
--- a/svx/source/table/svdotable.cxx
+++ b/svx/source/table/svdotable.cxx
@@ -204,6 +204,7 @@ public:
TableStyleSettings maTableStyle;
Reference< XIndexAccess > mxTableStyle;
std::vector<std::unique_ptr<SdrUndoAction>> maUndos;
+ bool mbSkipChangeLayout;
void SetModel(SdrModel* pOldModel, SdrModel* pNewModel);
@@ -260,6 +261,7 @@ sal_Int32 SdrTableObjImpl::lastColCount;
SdrTableObjImpl::SdrTableObjImpl()
: mpTableObj( nullptr )
, mpLayouter( nullptr )
+, mbSkipChangeLayout(false)
{
}
@@ -1868,7 +1870,11 @@ void SdrTableObj::NbcSetLogicRect(const Rectangle& rRect)
const bool bWidth = maLogicRect.getWidth() != maRect.getWidth();
const bool bHeight = maLogicRect.getHeight() != maRect.getHeight();
maRect = maLogicRect;
- NbcAdjustTextFrameWidthAndHeight( !bHeight, !bWidth );
+ if (mpImpl->mbSkipChangeLayout)
+ // Avoid distributing newly available space between existing cells.
+ NbcAdjustTextFrameWidthAndHeight(true, true);
+ else
+ NbcAdjustTextFrameWidthAndHeight(!bHeight, !bWidth);
SetRectsDirty();
}
@@ -2005,6 +2011,11 @@ void SdrTableObj::AddUndo(SdrUndoAction* pUndo)
mpImpl->maUndos.push_back(std::unique_ptr<SdrUndoAction>(pUndo));
}
+void SdrTableObj::SetSkipChangeLayout(bool bSkipChangeLayout)
+{
+ mpImpl->mbSkipChangeLayout = bSkipChangeLayout;
+}
+
// gets base transformation and rectangle of object. If it's an SdrPathObj it fills the PolyPolygon
// with the base geometry and returns TRUE. Otherwise it returns FALSE.
bool SdrTableObj::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& rPolyPolygon ) const
@@ -2247,6 +2258,7 @@ bool SdrTableObj::applySpecialDrag(SdrDragStat& rDrag)
if( GetModel() && IsInserted() )
{
rDrag.SetEndDragChangesAttributes(true);
+ rDrag.SetEndDragChangesLayout(true);
}
mpImpl->DragEdge( pEdgeHdl->IsHorizontalEdge(), pEdgeHdl->GetPointNum(), pEdgeHdl->GetValidDragOffset( rDrag ) );
diff --git a/svx/source/table/tablerow.cxx b/svx/source/table/tablerow.cxx
index ee95e905554b..cd82cc423b45 100644
--- a/svx/source/table/tablerow.cxx
+++ b/svx/source/table/tablerow.cxx
@@ -149,6 +149,10 @@ void TableRow::removeColumns( sal_Int32 nIndex, sal_Int32 nCount )
}
}
+TableModelRef TableRow::getModel() const
+{
+ return mxTableModel;
+}
// XCellRange
diff --git a/svx/source/table/tablerow.hxx b/svx/source/table/tablerow.hxx
index 77d654f23297..6b38b8037389 100644
--- a/svx/source/table/tablerow.hxx
+++ b/svx/source/table/tablerow.hxx
@@ -47,6 +47,8 @@ public:
void insertColumns( sal_Int32 nIndex, sal_Int32 nCount, CellVector::iterator* pIter = nullptr );
void removeColumns( sal_Int32 nIndex, sal_Int32 nCount );
+ /// Reference to the table model containing this row.
+ TableModelRef getModel() const;
// XCellRange
virtual css::uno::Reference< css::table::XCell > SAL_CALL getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow ) throw (css::lang::IndexOutOfBoundsException, css::uno::RuntimeException, std::exception) override;
diff --git a/svx/source/table/tableundo.cxx b/svx/source/table/tableundo.cxx
index baa7e6c29456..3a60ab02d0c2 100644
--- a/svx/source/table/tableundo.cxx
+++ b/svx/source/table/tableundo.cxx
@@ -463,6 +463,9 @@ void TableRowUndo::setData( const Data& rData )
mxRow->mbIsVisible = rData.mbIsVisible;
mxRow->mbIsStartOfNewPage = rData.mbIsStartOfNewPage;
mxRow->maName = rData.maName;
+
+ // Trigger re-layout of the table.
+ mxRow->getModel()->setModified(true);
}