sw/inc/bitmaps.hlst | 2 sw/qa/uitest/writer_tests/trackedChanges.py | 44 +++++++++ sw/source/uibase/inc/redlndlg.hxx | 3 sw/source/uibase/misc/redlndlg.cxx | 128 +++++++++++++++++----------- 4 files changed, 127 insertions(+), 50 deletions(-)
New commits: commit 6d2376bedd833fde2ae4bbf9d9557c1af188c007 Author: László Németh <nem...@numbertext.org> AuthorDate: Wed Jun 7 16:53:42 2023 +0200 Commit: László Németh <nem...@numbertext.org> CommitDate: Mon Jun 12 09:17:29 2023 +0200 tdf#155342 sw tracked table column: manage changes in Manage Changes dialog window, where deleted/inserted table columns were shown as multiple cell changes. Now deleted/inserted table columns are shown with a single tree item in the dialog window instead of showing multiple cell changes. Add new Action icons to the tracked table column insertion/deletion tree items (re-using table column deletion/insertion icons). Show cell changes as children of the single parent item tracked table column change. Accept/Reject and Accept/Reject All support 1-click acceptance or rejection of table column changes, instead of clicking on all cell changes of a single table column deletion/insertion. Follow-up to commit commit eebe4747d2d13545004937bb0267ccfc8ab9d63f "tdf#144270 sw: manage tracked table (row) deletion/insertion" and commit ffd8d20d368a885d6d786749278fa438573227a7 "tdf#150673 sw xmloff: import/export tracked table column". Change-Id: Ie9c9d8ef707ee2581cf6d0b066c10901555ca04c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152711 Tested-by: Jenkins Reviewed-by: László Németh <nem...@numbertext.org> (cherry picked from commit 67298969d80e106fd9a3727ab5d5a75fd8afd48c) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152815 diff --git a/sw/inc/bitmaps.hlst b/sw/inc/bitmaps.hlst index 6582b691d371..3d1e322af006 100644 --- a/sw/inc/bitmaps.hlst +++ b/sw/inc/bitmaps.hlst @@ -30,6 +30,8 @@ inline constexpr OUStringLiteral BMP_REDLINE_MOVED_INSERTION = u"cmd/sc_paste.pn inline constexpr OUStringLiteral BMP_REDLINE_MOVED_DELETION = u"cmd/sc_cut.png"; inline constexpr OUStringLiteral BMP_REDLINE_ROW_INSERTION = u"cmd/sc_insertrows.png"; inline constexpr OUStringLiteral BMP_REDLINE_ROW_DELETION = u"cmd/sc_deleterows.png"; +inline constexpr OUStringLiteral BMP_REDLINE_COL_INSERTION = u"cmd/sc_insertcolumns.png"; +inline constexpr OUStringLiteral BMP_REDLINE_COL_DELETION = u"cmd/sc_deletecolumns.png"; inline constexpr OUStringLiteral BMP_REDLINE_COMMENT_INSERTION = u"cmd/sc_insertannotation.png"; inline constexpr OUStringLiteral BMP_REDLINE_COMMENT_DELETION = u"cmd/sc_deleteannotation.png"; diff --git a/sw/qa/uitest/writer_tests/trackedChanges.py b/sw/qa/uitest/writer_tests/trackedChanges.py index a76cfe5dbe36..7e780ef61730 100644 --- a/sw/qa/uitest/writer_tests/trackedChanges.py +++ b/sw/qa/uitest/writer_tests/trackedChanges.py @@ -281,6 +281,9 @@ class trackedchanges(UITestCase): # Now: 4 changes (2 deleted/inserted rows and 2 deleted/inserted tables) self.assertEqual(4, len(changesList.getChildren())) + # jump to the parent to allow rejecting the table change + changesList.executeAction("TYPE", mkPropertyValues({"KEYCODE": "LEFT"})) + # Without the fix in place, it would have crashed here for i in (3, 2, 1, 0): xAccBtn = xTrackDlg.getChild("reject") @@ -500,4 +503,45 @@ class trackedchanges(UITestCase): # of the text "inserts": "Document text inserts document"... self.assertTrue(document.getText().getString().startswith('Document text document text')) + def test_tdf155342_tracked_table_colums(self): + with self.ui_test.load_file(get_url_for_data_file("TC-table-del-add.docx")) as document: + + # accept all changes and insert new columns with change tracking + self.xUITest.executeCommand(".uno:AcceptAllTrackedChanges") + tables = document.getTextTables() + self.assertEqual(2, len(tables)) + self.assertEqual(len(tables[0].getColumns()), 3) + self.xUITest.executeCommand(".uno:InsertColumnsAfter") + self.xUITest.executeCommand(".uno:InsertColumnsAfter") + self.assertEqual(len(tables[0].getColumns()), 5) + + xToolkit = self.xContext.ServiceManager.createInstance('com.sun.star.awt.Toolkit') + xToolkit.processEventsToIdle() + + # check and reject changes + with self.ui_test.execute_modeless_dialog_through_command(".uno:AcceptTrackedChanges", close_button="close") as xTrackDlg: + changesList = xTrackDlg.getChild("writerchanges") + + # six changes, but only one visible in the Manage Changes dialog window + state = get_state_as_dict(changesList) + self.assertEqual(state['Children'], '6') + self.assertEqual(state['VisibleCount'], '1') + + # This was 6 (every cell is a different change instead of counting column changes) + # Now: 1 changes (2 inserted columns) + self.assertEqual(1, len(changesList.getChildren())) + + # reject column insertion + + xAccBtn = xTrackDlg.getChild("reject") + xAccBtn.executeAction("CLICK", tuple()) + + # all inserted columns are removed + + self.assertEqual(len(tables[0].getColumns()), 3) + + # no changes in the dialog window + + self.assertEqual(0, len(changesList.getChildren())) + # vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/sw/source/uibase/inc/redlndlg.hxx b/sw/source/uibase/inc/redlndlg.hxx index 36be9513a932..7337f1fadce4 100644 --- a/sw/source/uibase/inc/redlndlg.hxx +++ b/sw/source/uibase/inc/redlndlg.hxx @@ -97,7 +97,8 @@ class SW_DLLPUBLIC SwRedlineAcceptDlg final SAL_DLLPRIVATE void RemoveParents(SwRedlineTable::size_type nStart, SwRedlineTable::size_type nEnd); SAL_DLLPRIVATE void InitAuthors(); - SAL_DLLPRIVATE static OUString GetActionImage(const SwRangeRedline& rRedln, sal_uInt16 nStack = 0, bool bRowChanges = false); + SAL_DLLPRIVATE static OUString GetActionImage(const SwRangeRedline& rRedln, sal_uInt16 nStack = 0, + bool bTableChanges = false, bool bRowChanges = false); SAL_DLLPRIVATE OUString GetActionText(const SwRangeRedline& rRedln, sal_uInt16 nStack = 0); SAL_DLLPRIVATE SwRedlineTable::size_type GetRedlinePos(const weld::TreeIter& rEntry); diff --git a/sw/source/uibase/misc/redlndlg.cxx b/sw/source/uibase/misc/redlndlg.cxx index 19374e5187a2..e583dc3af1a9 100644 --- a/sw/source/uibase/misc/redlndlg.cxx +++ b/sw/source/uibase/misc/redlndlg.cxx @@ -312,19 +312,24 @@ void SwRedlineAcceptDlg::InitAuthors() m_bOnlyFormatedRedlines ); } -OUString SwRedlineAcceptDlg::GetActionImage(const SwRangeRedline& rRedln, sal_uInt16 nStack, bool bRowChanges) +OUString SwRedlineAcceptDlg::GetActionImage(const SwRangeRedline& rRedln, sal_uInt16 nStack, + bool bTableChanges, bool bRowChanges) { switch (rRedln.GetType(nStack)) { - case RedlineType::Insert: return bRowChanges - ? OUString(BMP_REDLINE_ROW_INSERTION) + case RedlineType::Insert: return bTableChanges + ? bRowChanges + ? OUString(BMP_REDLINE_ROW_INSERTION) + : OUString(BMP_REDLINE_COL_INSERTION) : rRedln.IsMoved() ? OUString(BMP_REDLINE_MOVED_INSERTION) : rRedln.IsAnnotation() ? OUString(BMP_REDLINE_COMMENT_INSERTION) : OUString(BMP_REDLINE_INSERTED); - case RedlineType::Delete: return bRowChanges - ? OUString(BMP_REDLINE_ROW_DELETION) + case RedlineType::Delete: return bTableChanges + ? bRowChanges + ? OUString(BMP_REDLINE_ROW_DELETION) + : OUString(BMP_REDLINE_COL_DELETION) : rRedln.IsMoved() ? OUString(BMP_REDLINE_MOVED_DELETION) : rRedln.IsAnnotation() @@ -790,25 +795,23 @@ void SwRedlineAcceptDlg::InsertParents(SwRedlineTable::size_type nStart, SwRedli bool bIsShowChangesInMargin = SW_MOD()->GetUsrPref(false)->IsShowChangesInMargin(); - // collect redlines of tracked table or table row insertion/deletions under a single tree list - // item to accept/reject table (row) insertion/deletion with a single click on Accept/Reject + // collect redlines of tracked table/row/column insertion/deletions under a single tree list + // item to accept/reject the table change with a single click on Accept/Reject // Note: because update of the tree list depends on parent count, we don't modify // m_RedlineParents, only store the 2nd and more redlines as children of the tree list // item of the first redline // count of items stored as children (to adjust parent position) - sal_Int32 nSkipRedlines = 0; - // count of items of the actual table row (or joined table rows) stored as children = - // redlines of the row(s) - 1 (first redline is associated to the parent tree list item) - sal_Int32 nSkipRedline = 0; - // nSkipRedline of the previous table row (to join multiple table rows, if it's possible) - sal_Int32 nPrevSkipRedline = 0; - - // last SwRangeRedline in the table row + SwRedlineTable::size_type nSkipRedlines = 0; + // count of items of the actual table change stored as children = + // redlines of the change - 1 (first redline is associated to the parent tree list item) + SwRedlineTable::size_type nSkipRedline = 0; + + // last SwRangeRedline in the table row/column SwRedlineTable::size_type nLastChangeInRow = SwRedlineTable::npos; - // descriptor redline of the tracked table row - SwRedlineTable::size_type nRowChange = SwRedlineTable::npos; - // descriptor redline of the previous table row to join the table rows + // descriptor redline of the tracked table row/column + SwRedlineTable::size_type nRowChange = 0; + // descriptor redline of the previous table change to join with the next one SwRedlineTable::size_type nPrevRowChange = SwRedlineTable::npos; // show all redlines as tree list items, @@ -825,42 +828,69 @@ void SwRedlineAcceptDlg::InsertParents(SwRedlineTable::size_type nStart, SwRedli // handle tracked table row changes const SwTableBox* pTableBox; const SwTableLine* pTableLine; - // first SwRangeRedline of the tracked table row(s), base of the parent tree list - // of the other SwRangeRedlines of the tracked table row(s) + bool bChange = false; + bool bRowChange = false; + // first SwRangeRedline of the tracked table rows/columns, base of the parent tree list + // of the other SwRangeRedlines of the tracked table rows or columns SwRedlineTable::size_type nNewTableParent = SwRedlineTable::npos; if ( // not recognized yet as tracked table row change - nLastChangeInRow == SwRedlineTable::npos && nullptr != ( pTableBox = pSh->GetRedline(i).Start()->GetNode().GetTableBox() ) && nullptr != ( pTableLine = pTableBox->GetUpper() ) && - // it's a tracked row change based on the cached row data - RedlineType::None != pTableLine->GetRedlineType() ) + // it's a tracked row (or column change) based on the cached row data + ( RedlineType::None != pTableLine->GetRedlineType() || + RedlineType::None != pTableBox->GetRedlineType() ) ) { - SwRedlineTable::size_type nRedline = i; - nRowChange = pTableLine->UpdateTextChangesOnly(nRedline); + // start redline search from the start from the tracked row/column change + SwRedlineTable::size_type nStartPos = + nRowChange > nSkipRedline ? nRowChange - nSkipRedline : 0; + bChange = true; + bRowChange = RedlineType::None != pTableLine->GetRedlineType(); + nRowChange = bRowChange + ? pTableLine->UpdateTextChangesOnly(nStartPos) + : pTableBox->GetRedline(); if ( SwRedlineTable::npos != nRowChange ) { - nSkipRedline = nRedline - i - 1; - nLastChangeInRow = nRedline - 1; - // join the consecutive deleted/inserted rows under a single treebox item, + // redline is there in a tracked table change + + // join the consecutive deleted/inserted rows/columns under a single treebox item, // if they have the same redline data (equal type, author and time stamp) - if ( nPrevRowChange != SwRedlineTable::npos && - pSh->GetRedline(nRowChange).GetRedlineData() == pSh->GetRedline(nPrevRowChange).GetRedlineData() ) + if ( nPrevRowChange != SwRedlineTable::npos ) { - nSkipRedline += nPrevSkipRedline + 1; - nPrevSkipRedline = 0; - nPrevRowChange = SwRedlineTable::npos; + // note: CanCombine() allows a time frame to join the changes within a short + // time period: this avoid of falling apart of the tracked columns inserted + // by several clicks + if ( pSh->GetRedline(nRowChange).GetRedlineData() + .CanCombine(pSh->GetRedline(nPrevRowChange).GetRedlineData()) && + // in the same table? + pSh->GetRedline(nRowChange).Start()->GetNode().FindTableNode() == + pSh->GetRedline(nPrevRowChange).Start()->GetNode().FindTableNode() ) + { + nSkipRedline++; + } + else + { + nNewTableParent = i; + nLastChangeInRow = i; + nPrevRowChange = nRowChange; + } } else + { + nLastChangeInRow = i; nNewTableParent = i; + } } else + { + // redline is not in a tracked table change + bChange = bRowChange = false; nPrevRowChange = SwRedlineTable::npos; + } } else + // redline is not in a tracked table change nPrevRowChange = SwRedlineTable::npos; - bool bRowChange(SwRedlineTable::npos != nLastChangeInRow); - bool bShowDeletedTextAsComment = bIsShowChangesInMargin && RedlineType::Delete == rRedln.GetType() && rRedln.GetComment().isEmpty(); const OUString& sComment = bShowDeletedTextAsComment @@ -876,9 +906,9 @@ void SwRedlineAcceptDlg::InsertParents(SwRedlineTable::size_type nStart, SwRedli // use descriptor SwRangeRedline of the changed row, if needed to show // the correct redline type, author and time stamp of the tracked row change - const SwRangeRedline& rChangeRedln = pSh->GetRedline(bRowChange ? nRowChange : i); + const SwRangeRedline& rChangeRedln = pSh->GetRedline(bChange ? nRowChange : i); - OUString sImage = GetActionImage(rChangeRedln, 0, bRowChange && nNewTableParent != SwRedlineTable::npos ); + OUString sImage = GetActionImage(rChangeRedln, 0, bChange && nNewTableParent != SwRedlineTable::npos, bRowChange ); OUString sAuthor = rChangeRedln.GetAuthorString(0); pData->aDateTime = rChangeRedln.GetTimeStamp(0); pData->eType = rChangeRedln.GetType(0); @@ -887,12 +917,20 @@ void SwRedlineAcceptDlg::InsertParents(SwRedlineTable::size_type nStart, SwRedli OUString sId = weld::toId(pData.get()); std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator()); - if ( !bRowChange || nNewTableParent != SwRedlineTable::npos ) + if ( !bChange || nNewTableParent != SwRedlineTable::npos ) + { rTreeView.insert(nullptr, i - nSkipRedlines, nullptr, &sId, nullptr, nullptr, false, xParent.get()); + // before this was a tracked table change with more than a single redline + if ( nSkipRedline > 0 ) + { + nSkipRedlines += nSkipRedline; + nSkipRedline = 0; + } + } else { // put 2nd or more redlines of deleted/inserted rows as children of their first redline - SwRedlineDataParent *const pParent = m_RedlineParents[nLastChangeInRow - nSkipRedline].get(); + SwRedlineDataParent *const pParent = m_RedlineParents[nLastChangeInRow].get(); rTreeView.insert(pParent->xTLBParent.get(), -1, nullptr, &sId, nullptr, nullptr, false, xParent.get()); } @@ -916,16 +954,8 @@ void SwRedlineAcceptDlg::InsertParents(SwRedlineTable::size_type nStart, SwRedli InsertChildren(pRedlineParent, rRedln, bHasRedlineAutoFormat); - // end of a tracked deletion/insertion of a table row - if ( nLastChangeInRow != SwRedlineTable::npos && i == nLastChangeInRow ) - { - nSkipRedlines += nSkipRedline; - nPrevSkipRedline = nSkipRedline; - nSkipRedline = 0; - nPrevRowChange = nRowChange; - nNewTableParent = SwRedlineTable::npos; - nLastChangeInRow = SwRedlineTable::npos; - } + nPrevRowChange = nRowChange; + nNewTableParent = SwRedlineTable::npos; } rTreeView.thaw(); if (m_pTable->IsSorted())