From c8f3cffb91d72e68827450a46b22eb7f852feadd Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Wed, 8 Jun 2016 15:36:24 +0200 Subject: tdf#100269 svx: fix undo of table column resize SdrTableObjImpl::LayoutTable() assumed no re-layout is needed in case the total width of the table and the number of columns is the same, but undo of resize is a situation where we also need to check the individual widths of the columns, otherwise layout won't be up to date. (cherry picked from commits a106165e7fd39215c4717e1486aef05f6af9180f and 9cea9137b2534da4056f72d3c8a07f85a02f85be) Change-Id: Ia5ebb05af79dda1c0d8c5bb10e7f37f81ee1d035 Reviewed-on: https://gerrit.libreoffice.org/26071 Reviewed-by: Miklos Vajna Tested-by: Jenkins --- include/svx/svdotable.hxx | 2 + sd/qa/unit/tiledrendering/data/table-column.odp | Bin 0 -> 10526 bytes sd/qa/unit/tiledrendering/tiledrendering.cxx | 88 +++++++++++++++++++++++- svx/source/table/svdotable.cxx | 40 ++++++++++- svx/source/table/tablecolumn.cxx | 9 +++ svx/source/table/tablecolumn.hxx | 5 ++ svx/source/table/tablelayouter.cxx | 29 ++++++++ svx/source/table/tablelayouter.hxx | 2 + svx/source/table/tablemodel.cxx | 7 ++ svx/source/table/tablemodel.hxx | 2 + svx/source/table/tableundo.cxx | 3 + 11 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 sd/qa/unit/tiledrendering/data/table-column.odp diff --git a/include/svx/svdotable.hxx b/include/svx/svdotable.hxx index 5747e2bf3dde..b0e0c5c16d4c 100644 --- a/include/svx/svdotable.hxx +++ b/include/svx/svdotable.hxx @@ -281,6 +281,8 @@ public: static void ExportAsRTF( SvStream& rStrm, SdrTableObj& rObj ); static void ImportAsRTF( SvStream& rStrm, SdrTableObj& rObj ); + virtual void dumpAsXml(struct _xmlTextWriter* pWriter) const override; + private: void init( sal_Int32 nColumns, sal_Int32 nRows ); diff --git a/sd/qa/unit/tiledrendering/data/table-column.odp b/sd/qa/unit/tiledrendering/data/table-column.odp new file mode 100644 index 000000000000..d2c274e88856 Binary files /dev/null and b/sd/qa/unit/tiledrendering/data/table-column.odp differ diff --git a/sd/qa/unit/tiledrendering/tiledrendering.cxx b/sd/qa/unit/tiledrendering/tiledrendering.cxx index a47f99077267..b4b2ec6a1539 100644 --- a/sd/qa/unit/tiledrendering/tiledrendering.cxx +++ b/sd/qa/unit/tiledrendering/tiledrendering.cxx @@ -63,6 +63,7 @@ public: void testInsertTable(); void testPartHash(); void testResizeTable(); + void testResizeTableColumn(); #endif CPPUNIT_TEST_SUITE(SdTiledRenderingTest); @@ -83,6 +84,7 @@ public: CPPUNIT_TEST(testInsertTable); CPPUNIT_TEST(testPartHash); CPPUNIT_TEST(testResizeTable); + CPPUNIT_TEST(testResizeTableColumn); #endif CPPUNIT_TEST_SUITE_END(); @@ -91,6 +93,7 @@ private: SdXImpressDocument* createDoc(const char* pName); static void callback(int nType, const char* pPayload, void* pData); void callbackImpl(int nType, const char* pPayload); + xmlDocPtr parseXmlDump(); #endif uno::Reference mxComponent; @@ -106,6 +109,7 @@ private: /// For document size changed callback. osl::Condition m_aDocumentSizeCondition; + xmlBufferPtr m_pXmlBuffer; #endif }; @@ -114,7 +118,8 @@ SdTiledRenderingTest::SdTiledRenderingTest() : m_bFound(true), m_nPart(0), m_nSelectionBeforeSearchResult(0), - m_nSelectionAfterSearchResult(0) + m_nSelectionAfterSearchResult(0), + m_pXmlBuffer(nullptr) #endif { } @@ -131,6 +136,11 @@ void SdTiledRenderingTest::tearDown() if (mxComponent.is()) mxComponent->dispose(); +#if !defined(_WIN32) && !defined(MACOSX) + if (m_pXmlBuffer) + xmlBufferFree(m_pXmlBuffer); +#endif + test::BootstrapFixture::tearDown(); } @@ -238,6 +248,28 @@ void SdTiledRenderingTest::callbackImpl(int nType, const char* pPayload) } } +xmlDocPtr SdTiledRenderingTest::parseXmlDump() +{ + if (m_pXmlBuffer) + xmlBufferFree(m_pXmlBuffer); + + // Create the xml writer. + m_pXmlBuffer = xmlBufferCreate(); + xmlTextWriterPtr pXmlWriter = xmlNewTextWriterMemory(m_pXmlBuffer, 0); + xmlTextWriterStartDocument(pXmlWriter, nullptr, nullptr, nullptr); + + // Create the dump. + SdXImpressDocument* pImpressDocument = dynamic_cast(mxComponent.get()); + CPPUNIT_ASSERT(pImpressDocument); + pImpressDocument->GetDoc()->dumpAsXml(pXmlWriter); + + // Delete the xml writer. + xmlTextWriterEndDocument(pXmlWriter); + xmlFreeTextWriter(pXmlWriter); + + return xmlParseMemory(reinterpret_cast(xmlBufferContent(m_pXmlBuffer)), xmlBufferLength(m_pXmlBuffer)); +} + void SdTiledRenderingTest::testRegisterCallback() { SdXImpressDocument* pXImpressDocument = createDoc("dummy.odp"); @@ -729,6 +761,60 @@ void SdTiledRenderingTest::testResizeTable() comphelper::LibreOfficeKit::setActive(false); } +void SdTiledRenderingTest::testResizeTableColumn() +{ + // Load the document. + comphelper::LibreOfficeKit::setActive(); + SdXImpressDocument* pXImpressDocument = createDoc("table-column.odp"); + sd::ViewShell* pViewShell = pXImpressDocument->GetDocShell()->GetViewShell(); + SdPage* pActualPage = pViewShell->GetActualPage(); + SdrObject* pObject = pActualPage->GetObj(0); + auto pTableObject = dynamic_cast(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 cell widths. + xmlDocPtr pXmlDoc = parseXmlDump(); + OString aPrefix = "/sdDrawDocument/sdrModel/sdPage/sdrObjList/sdrTableObj/sdrTableObjImpl/tableLayouter/columns/"; + sal_Int32 nExpectedColumn1 = getXPath(pXmlDoc, aPrefix + "layout[1]", "size").toInt32(); + sal_Int32 nExpectedColumn2 = getXPath(pXmlDoc, aPrefix + "layout[2]", "size").toInt32(); + xmlFreeDoc(pXmlDoc); + pXmlDoc = nullptr; + + // Resize the left column, decrease its width 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() - 1000), convertMm100ToTwip(aInnerRowEdge.getY())); + + // Remember the resized column widths. + pXmlDoc = parseXmlDump(); + sal_Int32 nResizedColumn1 = getXPath(pXmlDoc, aPrefix + "layout[1]", "size").toInt32(); + CPPUNIT_ASSERT(nResizedColumn1 < nExpectedColumn1); + sal_Int32 nResizedColumn2 = getXPath(pXmlDoc, aPrefix + "layout[2]", "size").toInt32(); + CPPUNIT_ASSERT(nResizedColumn2 > nExpectedColumn2); + xmlFreeDoc(pXmlDoc); + pXmlDoc = nullptr; + + // Now undo the resize. + pXImpressDocument->GetDocShell()->GetUndoManager()->Undo(); + + // Check the undo result. + pXmlDoc = parseXmlDump(); + sal_Int32 nActualColumn1 = getXPath(pXmlDoc, aPrefix + "layout[1]", "size").toInt32(); + // Expected was 7049, actual was 6048, i.e. the first column width after undo was 1cm smaller than expected. + CPPUNIT_ASSERT_EQUAL(nExpectedColumn1, nActualColumn1); + sal_Int32 nActualColumn2 = getXPath(pXmlDoc, aPrefix + "layout[2]", "size").toInt32(); + CPPUNIT_ASSERT_EQUAL(nExpectedColumn2, nActualColumn2); + xmlFreeDoc(pXmlDoc); + pXmlDoc = nullptr; + comphelper::LibreOfficeKit::setActive(false); +} + #endif CPPUNIT_TEST_SUITE_REGISTRATION(SdTiledRenderingTest); diff --git a/svx/source/table/svdotable.cxx b/svx/source/table/svdotable.cxx index 2ea9c8abe954..8793f83928ec 100644 --- a/svx/source/table/svdotable.cxx +++ b/svx/source/table/svdotable.cxx @@ -57,6 +57,7 @@ #include "svx/xflftrit.hxx" #include "svx/xfltrit.hxx" #include +#include using ::com::sun::star::uno::Any; @@ -221,6 +222,8 @@ public: void dispose(); sal_Int32 getColumnCount() const; + /// Get widths of the columns in the table. + std::vector getColumnWidths() const; sal_Int32 getRowCount() const; void DragEdge( bool mbHorizontal, int nEdge, sal_Int32 nOffset ); @@ -238,6 +241,7 @@ public: void connectTableStyle(); void disconnectTableStyle(); virtual bool isInUse() override; + void dumpAsXml(struct _xmlTextWriter* pWriter) const; private: static SdrTableObjImpl* lastLayoutTable; static Rectangle lastLayoutInputRectangle; @@ -247,6 +251,7 @@ private: static WritingMode lastLayoutMode; static sal_Int32 lastRowCount; static sal_Int32 lastColCount; + static std::vector lastColWidths; }; SdrTableObjImpl* SdrTableObjImpl::lastLayoutTable = nullptr; @@ -257,6 +262,7 @@ bool SdrTableObjImpl::lastLayoutFitHeight; WritingMode SdrTableObjImpl::lastLayoutMode; sal_Int32 SdrTableObjImpl::lastRowCount; sal_Int32 SdrTableObjImpl::lastColCount; +std::vector SdrTableObjImpl::lastColWidths; SdrTableObjImpl::SdrTableObjImpl() : mpTableObj( nullptr ) @@ -624,6 +630,14 @@ bool SdrTableObjImpl::isInUse() return mpTableObj && mpTableObj->IsInserted(); } +void SdrTableObjImpl::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + xmlTextWriterStartElement(pWriter, BAD_CAST("sdrTableObjImpl")); + if (mpLayouter) + mpLayouter->dumpAsXml(pWriter); + xmlTextWriterEndElement(pWriter); +} + // XEventListener @@ -661,6 +675,15 @@ sal_Int32 SdrTableObjImpl::getColumnCount() const return mxTable.is() ? mxTable->getColumnCount() : 0; } +std::vector SdrTableObjImpl::getColumnWidths() const +{ + std::vector aRet; + + if (mxTable.is()) + aRet = mxTable->getColumnWidths(); + + return aRet; +} sal_Int32 SdrTableObjImpl::getRowCount() const { @@ -681,7 +704,8 @@ void SdrTableObjImpl::LayoutTable( Rectangle& rArea, bool bFitWidth, bool bFitHe || lastLayoutFitWidth != bFitWidth || lastLayoutFitHeight != bFitHeight || lastLayoutMode != writingMode || lastRowCount != getRowCount() - || lastColCount != getColumnCount() ) + || lastColCount != getColumnCount() + || lastColWidths != getColumnWidths() ) { lastLayoutTable = this; lastLayoutInputRectangle = rArea; @@ -690,6 +714,9 @@ void SdrTableObjImpl::LayoutTable( Rectangle& rArea, bool bFitWidth, bool bFitHe lastLayoutMode = writingMode; lastRowCount = getRowCount(); lastColCount = getColumnCount(); + // Column resize, when the total width and column count of the + // table is unchanged, but re-layout is still needed. + lastColWidths = getColumnWidths(); TableModelNotifyGuard aGuard( mxTable.get() ); mpLayouter->LayoutTable( rArea, bFitWidth, bFitHeight ); lastLayoutResultRectangle = rArea; @@ -2500,6 +2527,17 @@ void SdrTableObj::uno_unlock() mpImpl->mxTable->unlockBroadcasts(); } +void SdrTableObj::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + xmlTextWriterStartElement(pWriter, BAD_CAST("sdrTableObj")); + xmlTextWriterWriteFormatAttribute(pWriter, BAD_CAST("ptr"), "%p", this); + + SdrObject::dumpAsXml(pWriter); + + mpImpl->dumpAsXml(pWriter); + + xmlTextWriterEndElement(pWriter); +} } } diff --git a/svx/source/table/tablecolumn.cxx b/svx/source/table/tablecolumn.cxx index 597da0bb6d3b..c5ceadee0680 100644 --- a/svx/source/table/tablecolumn.cxx +++ b/svx/source/table/tablecolumn.cxx @@ -283,6 +283,15 @@ rtl::Reference< FastPropertySetInfo > TableColumn::getStaticPropertySetInfo() return xInfo; } +TableModelRef TableColumn::getModel() const +{ + return mxTableModel; +} + +sal_Int32 TableColumn::getWidth() const +{ + return mnWidth; +} } } diff --git a/svx/source/table/tablecolumn.hxx b/svx/source/table/tablecolumn.hxx index 9c81c69d718c..0c5083d5ce8f 100644 --- a/svx/source/table/tablecolumn.hxx +++ b/svx/source/table/tablecolumn.hxx @@ -58,6 +58,11 @@ public: virtual void SAL_CALL setFastPropertyValue( ::sal_Int32 nHandle, const css::uno::Any& aValue ) throw (css::beans::UnknownPropertyException, css::beans::PropertyVetoException, css::lang::IllegalArgumentException, css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception) override; virtual css::uno::Any SAL_CALL getFastPropertyValue( ::sal_Int32 nHandle ) throw (css::beans::UnknownPropertyException, css::lang::WrappedTargetException, css::uno::RuntimeException, std::exception) override; + /// Get the table that owns this column. + TableModelRef getModel() const; + /// Get the width of this column. + sal_Int32 getWidth() const; + private: static rtl::Reference< FastPropertySetInfo > getStaticPropertySetInfo(); diff --git a/svx/source/table/tablelayouter.cxx b/svx/source/table/tablelayouter.cxx index 0f6208c54f1d..ae87f5044ad3 100644 --- a/svx/source/table/tablelayouter.cxx +++ b/svx/source/table/tablelayouter.cxx @@ -21,6 +21,7 @@ #include #include +#include #include "cell.hxx" #include "cellrange.hxx" @@ -1121,6 +1122,34 @@ void TableLayouter::DistributeRows( ::Rectangle& rArea, sal_Int32 nFirstRow, sal } } +void TableLayouter::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + xmlTextWriterStartElement(pWriter, BAD_CAST("tableLayouter")); + + xmlTextWriterStartElement(pWriter, BAD_CAST("columns")); + for (const auto& rColumn : maColumns) + rColumn.dumpAsXml(pWriter); + xmlTextWriterEndElement(pWriter); + + xmlTextWriterStartElement(pWriter, BAD_CAST("rows")); + for (const auto& rRow : maRows) + rRow.dumpAsXml(pWriter); + xmlTextWriterEndElement(pWriter); + + xmlTextWriterEndElement(pWriter); +} + +void TableLayouter::Layout::dumpAsXml(xmlTextWriterPtr pWriter) const +{ + xmlTextWriterStartElement(pWriter, BAD_CAST("layout")); + + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("pos"), BAD_CAST(OString::number(mnPos).getStr())); + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("size"), BAD_CAST(OString::number(mnSize).getStr())); + xmlTextWriterWriteAttribute(pWriter, BAD_CAST("minSize"), BAD_CAST(OString::number(mnMinSize).getStr())); + + xmlTextWriterEndElement(pWriter); +} + } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/svx/source/table/tablelayouter.hxx b/svx/source/table/tablelayouter.hxx index b38345588a54..0ab692c2591c 100644 --- a/svx/source/table/tablelayouter.hxx +++ b/svx/source/table/tablelayouter.hxx @@ -96,6 +96,7 @@ public: void DistributeColumns( ::Rectangle& rArea, sal_Int32 nFirstCol, sal_Int32 nLastCol ); void DistributeRows( ::Rectangle& rArea, sal_Int32 nFirstRow, sal_Int32 nLastRow ); + void dumpAsXml(struct _xmlTextWriter* pWriter) const; private: CellRef getCell( const CellPos& rPos ) const; @@ -125,6 +126,7 @@ private: Layout() : mnPos( 0 ), mnSize( 0 ), mnMinSize( 0 ) {} void clear() { mnPos = 0; mnSize = 0; mnMinSize = 0; } + void dumpAsXml(struct _xmlTextWriter* pWriter) const; }; typedef std::vector< Layout > LayoutVector; diff --git a/svx/source/table/tablemodel.cxx b/svx/source/table/tablemodel.cxx index b6dd24579eb3..e7062289ca48 100644 --- a/svx/source/table/tablemodel.cxx +++ b/svx/source/table/tablemodel.cxx @@ -321,6 +321,13 @@ sal_Int32 SAL_CALL TableModel::getColumnCount() throw (RuntimeException, std::ex return getColumnCountImpl(); } +std::vector TableModel::getColumnWidths() +{ + std::vector aRet; + for (const TableColumnRef& xColumn : maColumns) + aRet.push_back(xColumn->getWidth()); + return aRet; +} // XComponent diff --git a/svx/source/table/tablemodel.hxx b/svx/source/table/tablemodel.hxx index 66263e64cfe7..411bf2f97c59 100644 --- a/svx/source/table/tablemodel.hxx +++ b/svx/source/table/tablemodel.hxx @@ -81,6 +81,8 @@ public: /// merges the cell at the given position with the given span void merge( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nColSpan, sal_Int32 nRowSpan ); + /// Get the width of all columns in this table. + std::vector getColumnWidths(); // ICellRange virtual sal_Int32 getLeft() override; diff --git a/svx/source/table/tableundo.cxx b/svx/source/table/tableundo.cxx index 3a60ab02d0c2..cb0093fbc80e 100644 --- a/svx/source/table/tableundo.cxx +++ b/svx/source/table/tableundo.cxx @@ -400,6 +400,9 @@ void TableColumnUndo::setData( const Data& rData ) mxCol->mbIsVisible = rData.mbIsVisible; mxCol->mbIsStartOfNewPage = rData.mbIsStartOfNewPage; mxCol->maName = rData.maName; + + // Trigger re-layout of the table. + mxCol->getModel()->setModified(true); } -- cgit v1.2.3