sw/qa/extras/ooxmlexport/data/TC-table-DnD-move.docx |binary sw/qa/extras/ooxmlexport/data/TC-table-Separate-Move.docx |binary sw/qa/extras/ooxmlexport/data/TC-table-rowDND-front.docx |binary sw/qa/extras/ooxmlexport/data/TC-table-rowDND.docx |binary sw/qa/extras/ooxmlexport/ooxmlexport11.cxx | 50 ++++++++++++++ writerfilter/source/dmapper/DomainMapper.cxx | 13 +++ writerfilter/source/dmapper/DomainMapperTableManager.cxx | 17 ++++ writerfilter/source/dmapper/DomainMapperTableManager.hxx | 37 ++++++++++ writerfilter/source/ooxml/model.xml | 4 + 9 files changed, 121 insertions(+)
New commits: commit 5602803d07453bfd7c17ed5b6df7551d1041f97c Author: László Németh <nem...@numbertext.org> AuthorDate: Thu Jul 22 19:08:47 2021 +0200 Commit: László Németh <nem...@numbertext.org> CommitDate: Mon Jul 26 12:09:10 2021 +0200 tdf#143510 DOCX import: fix tracked table drag & drop Accept or reject of tracked drag & drop table (row) move weren't handled, resulting an extra empty table (rows) instead of removing the deleted or inserted table (rows). Note: tables moved by drag & drop with track changes use w:moveFromRangeStart/End and w:moveToRangeStart/End bookmark-like elements to sign the boundary of the moved text. Now moveFrom/moveTo import is handled by tracked table (row) deletion and insertion. Change-Id: Ie382645fef28f57b30d3504fb28ac08489f705c0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119406 Tested-by: Jenkins Reviewed-by: László Németh <nem...@numbertext.org> (cherry picked from commit 7f3c0bbc174b9b0316991c174ca3b407c0e3d141) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119436 diff --git a/sw/qa/extras/ooxmlexport/data/TC-table-DnD-move.docx b/sw/qa/extras/ooxmlexport/data/TC-table-DnD-move.docx new file mode 100644 index 000000000000..f231d6f84240 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/TC-table-DnD-move.docx differ diff --git a/sw/qa/extras/ooxmlexport/data/TC-table-Separate-Move.docx b/sw/qa/extras/ooxmlexport/data/TC-table-Separate-Move.docx new file mode 100644 index 000000000000..227f2862c68a Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/TC-table-Separate-Move.docx differ diff --git a/sw/qa/extras/ooxmlexport/data/TC-table-rowDND-front.docx b/sw/qa/extras/ooxmlexport/data/TC-table-rowDND-front.docx new file mode 100644 index 000000000000..17d3feeb3406 Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/TC-table-rowDND-front.docx differ diff --git a/sw/qa/extras/ooxmlexport/data/TC-table-rowDND.docx b/sw/qa/extras/ooxmlexport/data/TC-table-rowDND.docx new file mode 100644 index 000000000000..9608736cf20a Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/TC-table-rowDND.docx differ diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx index 1864c4bcf83e..431d5d71753d 100644 --- a/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx +++ b/sw/qa/extras/ooxmlexport/ooxmlexport11.cxx @@ -881,6 +881,56 @@ DECLARE_OOXMLEXPORT_TEST(testTdf104797, "tdf104797.docx") CPPUNIT_ASSERT_EQUAL( OUString( " Will this sentence be duplicated ADDED STUFF?" ), getRun( getParagraph( 2 ), 4 )->getString()); } +DECLARE_OOXMLEXPORT_TEST(testTdf143510, "TC-table-DnD-move.docx") +{ + // check moveFromRangeStart/End and moveToRangeStart/End for tracked table move by drag & drop + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + if (mbExported) + { + // This was 0 (missing tracked table row deletion/insertion) + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl[1]/w:tr/w:trPr/w:del", 2); + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl[2]/w:tr/w:trPr/w:ins", 2); + } +} + +DECLARE_OOXMLEXPORT_TEST(testTdf143510_table_from_row, "TC-table-Separate-Move.docx") +{ + // check moveFromRangeStart/End and moveToRangeStart/End for tracked table move by drag & drop + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + if (mbExported) + { + // This was 0 (missing tracked table row deletion/insertion) + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl[1]/w:tr/w:trPr/w:del", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl[1]/w:tr[3]/w:trPr/w:del", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl[2]/w:tr", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl[2]/w:tr/w:trPr/w:ins", 1); + } +} + +DECLARE_OOXMLEXPORT_TEST(testTdf143510_within_table, "TC-table-rowDND.docx") +{ + // check moveFromRangeStart/End and moveToRangeStart/End for tracked table row move by DnD + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + if (mbExported) + { + // This was 0 (missing tracked table row deletion/insertion) + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl/w:tr[1]/w:trPr/w:del", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl/w:tr[4]/w:trPr/w:ins", 1); + } +} + +DECLARE_OOXMLEXPORT_TEST(testTdf143510_within_table2, "TC-table-rowDND-front.docx") +{ + // check moveFromRangeStart/End and moveToRangeStart/End for tracked table row move by DnD + xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml"); + if (mbExported) + { + // This was 0 (missing tracked table row deletion/insertion) + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl/w:tr[1]/w:trPr/w:ins", 1); + assertXPath(pXmlDoc, "/w:document/w:body/w:tbl/w:tr[4]/w:trPr/w:del", 1); + } +} + DECLARE_OOXMLEXPORT_TEST(testTdf113608_runAwayNumbering, "tdf113608_runAwayNumbering.docx") { // check that an incorrect numbering style is not applied diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx index 182b7c5c3200..232650c7f8ea 100644 --- a/writerfilter/source/dmapper/DomainMapper.cxx +++ b/writerfilter/source/dmapper/DomainMapper.cxx @@ -2454,6 +2454,19 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext ) } } break; + case NS_ooxml::LN_EG_RangeMarkupElements_moveFromRangeStart: + if (m_pImpl->hasTableManager()) + m_pImpl->getTableManager().setMoved( getPropertyName(PROP_TABLE_ROW_DELETE) ); + break; + case NS_ooxml::LN_EG_RangeMarkupElements_moveToRangeStart: + if (m_pImpl->hasTableManager()) + m_pImpl->getTableManager().setMoved( getPropertyName(PROP_TABLE_ROW_INSERT) ); + break; + case NS_ooxml::LN_EG_RangeMarkupElements_moveFromRangeEnd: + case NS_ooxml::LN_EG_RangeMarkupElements_moveToRangeEnd: + if (m_pImpl->hasTableManager()) + m_pImpl->getTableManager().setMoved( OUString() ); + break; case NS_ooxml::LN_paratrackchange: m_pImpl->StartParaMarkerChange( ); [[fallthrough]]; diff --git a/writerfilter/source/dmapper/DomainMapperTableManager.cxx b/writerfilter/source/dmapper/DomainMapperTableManager.cxx index a3a76dccbf82..35749d60bd59 100644 --- a/writerfilter/source/dmapper/DomainMapperTableManager.cxx +++ b/writerfilter/source/dmapper/DomainMapperTableManager.cxx @@ -30,6 +30,8 @@ #include <rtl/math.hxx> #include <sal/log.hxx> #include <numeric> +#include "TrackChangesHandler.hxx" +#include <oox/token/tokens.hxx> namespace writerfilter::dmapper { @@ -449,6 +451,7 @@ void DomainMapperTableManager::startLevel( ) m_aTablePositions.push_back( pNewPositionHandler ); // empty name will be replaced by the table style name, if it exists m_aTableStyleNames.push_back( OUString() ); + m_aMoved.push_back( OUString() ); TablePositionHandlerPtr pTmpPosition; TablePropertyMapPtr pTmpProperties( new TablePropertyMap( ) ); @@ -507,6 +510,7 @@ void DomainMapperTableManager::endLevel( ) // in the endTable method called in endLevel. m_aTablePositions.pop_back(); m_aTableStyleNames.pop_back(); + m_aMoved.pop_back( ); m_aParagraphsToEndTable.pop(); } @@ -727,6 +731,19 @@ void DomainMapperTableManager::endOfRowAction() pPropMap->dumpXml(); TagLogger::getInstance().endElement(); #endif + + // set row insertion/deletion at tracked drag & drop of tables + OUString aMoved = getMoved(); + if ( !aMoved.isEmpty() ) + { + auto pTrackChangesHandler = std::make_shared<TrackChangesHandler>( + aMoved == getPropertyName( PROP_TABLE_ROW_DELETE ) + ? oox::XML_tableRowDelete + : oox::XML_tableRowInsert ); + uno::Sequence<beans::PropertyValue> aTableRedlineProperties = pTrackChangesHandler->getRedlineProperties(); + pPropMap->Insert( PROP_TABLE_REDLINE_PARAMS , uno::makeAny( aTableRedlineProperties )); + } + insertRowProps(pPropMap); } else if (shouldInsertRow(pCellWidths, pTableGrid, nGrids, bIsIncompleteGrid)) diff --git a/writerfilter/source/dmapper/DomainMapperTableManager.hxx b/writerfilter/source/dmapper/DomainMapperTableManager.hxx index 8c337e6b48c8..ef90297c5b97 100644 --- a/writerfilter/source/dmapper/DomainMapperTableManager.hxx +++ b/writerfilter/source/dmapper/DomainMapperTableManager.hxx @@ -43,6 +43,8 @@ class DomainMapperTableManager : public TableManager /// Are we in a shape (text append stack is not empty) or in the body document? bool m_bIsInShape; std::vector< OUString > m_aTableStyleNames; + /// Moved table (in moveRangeFromStart...moveRangeFromEnd or moveRangeToStart...moveRangeToEnd) + std::vector< OUString > m_aMoved; /// Grab-bag of table look attributes for preserving. comphelper::SequenceAsHashMap m_aTableLook; std::vector< TablePositionHandlerPtr > m_aTablePositions; @@ -128,6 +130,41 @@ public: void setIsInShape(bool bIsInShape); + // moveFromRangeStart and moveToRangeStart are there + // in the first paragraph in the first cell of the + // table moved by drag & drop with track changes, but + // moveFromRangeEnd and moveToRangeEnd follow the + // table element w:tbl in the same level (not in paragraph). + // (Special indexing is related to the load of the tables: + // first-level tables handled by two levels during the + // import, to support table join etc. In the first cell, + // setMoved() writes the first level from these two levels + // i.e. second startLevel() hasn't been called, yet.) + // TODO: check drag & drop of only a part of the tables. + void setMoved(OUString sMoved) + { + if ( m_aMoved.empty() ) + return; + + if ( !sMoved.isEmpty() ) + m_aMoved.end()[-1] = sMoved; + else if ( m_aMoved.size() >= 2 ) + // next table rows weren't moved + m_aMoved.end()[-2] = ""; + else + m_aMoved.end()[-1] = ""; + } + + OUString getMoved() const + { + if ( m_aMoved.size() >= 2 && !m_aMoved.end()[-2].isEmpty() ) + return m_aMoved.end()[-2]; + else if ( !m_aMoved.empty() ) + return m_aMoved.end()[-1]; + + return OUString(); + } + }; } diff --git a/writerfilter/source/ooxml/model.xml b/writerfilter/source/ooxml/model.xml index 77dce046fb3d..da6d56473d41 100644 --- a/writerfilter/source/ooxml/model.xml +++ b/writerfilter/source/ooxml/model.xml @@ -17472,6 +17472,8 @@ </resource> <resource name="CT_MarkupRangeBookmark" resource="Properties"> <attribute name="id" tokenid="ooxml:CT_MarkupRangeBookmark_id"/> + <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveFromRangeEnd"/> + <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeEnd" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveToRangeEnd"/> </resource> <resource name="CT_PermStart" resource="Properties"> <attribute name="id" tokenid="ooxml:CT_PermStart_id"/> @@ -17501,6 +17503,8 @@ <resource name="CT_MoveBookmark" resource="Properties"> <attribute name="author" tokenid="ooxml:CT_MoveBookmark_author"/> <attribute name="date" tokenid="ooxml:CT_MoveBookmark_date"/> + <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveFromRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveFromRangeStart"/> + <action name="end" tokenid="ooxml:EG_RangeMarkupElements_moveToRangeStart" action="sendPropertiesWithId" sendtokenid="ooxml:EG_RangeMarkupElements_moveToRangeStart"/> </resource> <resource name="CT_Comment" resource="XNote"> <attribute name="id" action="checkId"/> _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits