diff options
-rw-r--r-- | offapi/com/sun/star/text/TextTableRow.idl | 8 | ||||
-rw-r--r-- | sw/inc/doc.hxx | 2 | ||||
-rw-r--r-- | sw/inc/swtable.hxx | 2 | ||||
-rw-r--r-- | sw/inc/unoprnms.hxx | 1 | ||||
-rw-r--r-- | sw/qa/extras/uiwriter/uiwriter2.cxx | 77 | ||||
-rw-r--r-- | sw/source/core/bastyp/init.cxx | 2 | ||||
-rw-r--r-- | sw/source/core/doc/DocumentRedlineManager.cxx | 34 | ||||
-rw-r--r-- | sw/source/core/docnode/ndtbl1.cxx | 26 | ||||
-rw-r--r-- | sw/source/core/frmedt/fetab.cxx | 30 | ||||
-rw-r--r-- | sw/source/core/table/swtable.cxx | 15 | ||||
-rw-r--r-- | sw/source/core/unocore/unomap.cxx | 1 | ||||
-rw-r--r-- | sw/source/filter/html/htmltab.cxx | 17 |
12 files changed, 199 insertions, 16 deletions
diff --git a/offapi/com/sun/star/text/TextTableRow.idl b/offapi/com/sun/star/text/TextTableRow.idl index d640d1c06cce..77191c9f57d1 100644 --- a/offapi/com/sun/star/text/TextTableRow.idl +++ b/offapi/com/sun/star/text/TextTableRow.idl @@ -105,6 +105,14 @@ published service TextTableRow @since LibreOffice 6.1 */ [optional, property] com::sun::star::graphic::XGraphic BackGraphic; + + /** If TRUE, the table row wasn't deleted or inserted with its tracked cell content + + @since LibreOffice 7.2 + */ + + [optional, property, maybevoid] boolean IsNotTracked; + }; diff --git a/sw/inc/doc.hxx b/sw/inc/doc.hxx index 08510f634569..19a2b6af64b1 100644 --- a/sw/inc/doc.hxx +++ b/sw/inc/doc.hxx @@ -1489,6 +1489,8 @@ public: bool BalanceRowHeight( const SwCursor& rCursor, bool bTstOnly, const bool bOptimize ); void SetRowBackground( const SwCursor& rCursor, const SvxBrushItem &rNew ); static bool GetRowBackground( const SwCursor& rCursor, std::unique_ptr<SvxBrushItem>& rToFill ); + /// rNotTracked = false means that the row was deleted or inserted with its tracked cell content + void SetRowNotTracked( const SwCursor& rCursor, const SvxPrintItem &rNotTracked ); void SetTabBorders( const SwCursor& rCursor, const SfxItemSet& rSet ); void SetTabLineStyle( const SwCursor& rCursor, const Color* pColor, bool bSetLine, diff --git a/sw/inc/swtable.hxx b/sw/inc/swtable.hxx index 5432a24d60e4..6696c94d6cfc 100644 --- a/sw/inc/swtable.hxx +++ b/sw/inc/swtable.hxx @@ -444,6 +444,8 @@ public: void RemoveFromTable(); const SwStartNode *GetSttNd() const { return m_pStartNode; } sal_uLong GetSttIdx() const; + // it doesn't contain box content + bool IsEmpty() const; // Search next/previous box with content. SwTableBox* FindNextBox( const SwTable&, const SwTableBox*, diff --git a/sw/inc/unoprnms.hxx b/sw/inc/unoprnms.hxx index 9cceac0f8d0f..317ad79fa8ed 100644 --- a/sw/inc/unoprnms.hxx +++ b/sw/inc/unoprnms.hxx @@ -736,6 +736,7 @@ #define UNO_NAME_ITEMS "Items" #define UNO_NAME_SELITEM "SelectedItem" #define UNO_NAME_IS_SPLIT_ALLOWED "IsSplitAllowed" +#define UNO_NAME_IS_NOT_TRACKED "IsNotTracked" #define UNO_NAME_CHAR_HIDDEN "CharHidden" #define UNO_NAME_IS_FOLLOWING_TEXT_FLOW "IsFollowingTextFlow" #define UNO_NAME_WIDTH_TYPE "WidthType" diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx index 02d8163cc95e..d1323c8104d5 100644 --- a/sw/qa/extras/uiwriter/uiwriter2.cxx +++ b/sw/qa/extras/uiwriter/uiwriter2.cxx @@ -3666,6 +3666,83 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf118311) assertXPath(pXmlDoc, "//page[1]//body/tab", 0); } +CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testRedlineTableRowDeletion) +{ + // load a 1-row table, and delete the row with enabled change tracking: + // now the row is not deleted silently, but keeps the deleted cell contents, + // and only accepting all of them will result the deletion of the table row. + SwDoc* pDoc = createDoc("tdf118311.fodt"); + + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + CPPUNIT_ASSERT(pTextDoc); + + // turn on red-lining and show changes + pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On | RedlineFlags::ShowDelete + | RedlineFlags::ShowInsert); + CPPUNIT_ASSERT_MESSAGE("redlining should be on", + pDoc->getIDocumentRedlineAccess().IsRedlineOn()); + CPPUNIT_ASSERT_MESSAGE( + "redlines should be visible", + IDocumentRedlineAccess::IsShowChanges(pDoc->getIDocumentRedlineAccess().GetRedlineFlags())); + + // check table + xmlDocUniquePtr pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab"); + + // delete table row with enabled change tracking + dispatchCommand(mxComponent, ".uno:DeleteRows", {}); + + // This was deleted without change tracking + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab"); + + // accept the deletion of the content of the first cell + + SwEditShell* const pEditShell(pDoc->GetEditShell()); + CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(2), pEditShell->GetRedlineCount()); + pEditShell->AcceptRedline(0); + + // table row was still not deleted + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab"); + + // accept last redline + pEditShell->AcceptRedline(0); + + // table row (and the 1-row table) was deleted finally + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab", 0); + + // Undo, and delete the row without change tracking + + dispatchCommand(mxComponent, ".uno:Undo", {}); + dispatchCommand(mxComponent, ".uno:Undo", {}); + dispatchCommand(mxComponent, ".uno:Undo", {}); + + // table exists again + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab"); + + // disable change tracking + pDoc->getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::ShowDelete + | RedlineFlags::ShowInsert); + + CPPUNIT_ASSERT_MESSAGE("redlining should be off", + !pDoc->getIDocumentRedlineAccess().IsRedlineOn()); + + // delete table row without change tracking + dispatchCommand(mxComponent, ".uno:DeleteRows", {}); + + // the table (row) was deleted + discardDumpedLayout(); + pXmlDoc = parseLayoutDump(); + assertXPath(pXmlDoc, "//page[1]//body/tab", 0); +} + CPPUNIT_TEST_FIXTURE(SwUiWriterTest2, testTdf128335) { // Load the bugdoc, which has 3 textboxes. diff --git a/sw/source/core/bastyp/init.cxx b/sw/source/core/bastyp/init.cxx index 19d2f12d9a3a..f1b86f8dfdc0 100644 --- a/sw/source/core/bastyp/init.cxx +++ b/sw/source/core/bastyp/init.cxx @@ -206,6 +206,8 @@ sal_uInt16 const aTableSetRange[] = { sal_uInt16 const aTableLineSetRange[] = { RES_FILL_ORDER, RES_FRM_SIZE, + // IsNotTracked + RES_PRINT, RES_PRINT, RES_LR_SPACE, RES_UL_SPACE, RES_BACKGROUND, RES_SHADOW, RES_ROW_SPLIT, RES_ROW_SPLIT, diff --git a/sw/source/core/doc/DocumentRedlineManager.cxx b/sw/source/core/doc/DocumentRedlineManager.cxx index 1c63619a8e1b..0e92f16034a5 100644 --- a/sw/source/core/doc/DocumentRedlineManager.cxx +++ b/sw/source/core/doc/DocumentRedlineManager.cxx @@ -38,6 +38,7 @@ #include <strings.hrc> #include <swmodule.hxx> #include <osl/diagnose.h> +#include <editeng/prntitem.hxx> using namespace com::sun::star; @@ -430,6 +431,36 @@ namespace return nullptr; } + // delete the empty tracked table row (i.e. if it's last tracked deletion was accepted) + void lcl_DeleteTrackedTableRow ( SwPosition* pPos ) + { + if ( const SwTableBox* pBox = pPos->nNode.GetNode().GetTableBox() ) + { + const SwTableLine* pLine = pBox->GetUpper(); + const SvxPrintItem *pIsNoTrackedProp = + pLine->GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT); + // table row property "IsNotTracked" is set and its value is false + if ( pIsNoTrackedProp && !pIsNoTrackedProp->GetValue() ) + { + bool bEmptyLine = true; + const SwTableBoxes & rBoxes = pLine->GetTabBoxes(); + for (size_t nBox = 0; nBox < rBoxes.size(); ++nBox) + { + if ( !rBoxes[nBox]->IsEmpty() ) + { + bEmptyLine = false; + break; + } + } + if ( bEmptyLine ) + { + SwCursor aCursor( *pPos, nullptr ); + pPos->GetDoc().DeleteRow( aCursor ); + } + } + } + } + bool lcl_AcceptRedline( SwRedlineTable& rArr, SwRedlineTable::size_type& rPos, bool bCallDelete, const SwPosition* pSttRng = nullptr, @@ -565,7 +596,10 @@ namespace rDoc.getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld & ~RedlineFlags(RedlineFlags::On | RedlineFlags::Ignore)); if( pCSttNd && pCEndNd ) + { rDoc.getIDocumentContentOperations().DeleteAndJoin( aPam ); + lcl_DeleteTrackedTableRow( aPam.End() ); + } else if (pCSttNd && !pCEndNd) { aPam.GetBound().nContent.Assign( nullptr, 0 ); diff --git a/sw/source/core/docnode/ndtbl1.cxx b/sw/source/core/docnode/ndtbl1.cxx index 6d2a677712be..9a4f80ee995a 100644 --- a/sw/source/core/docnode/ndtbl1.cxx +++ b/sw/source/core/docnode/ndtbl1.cxx @@ -536,6 +536,32 @@ bool SwDoc::GetRowBackground( const SwCursor& rCursor, std::unique_ptr<SvxBrushI return bRet; } +void SwDoc::SetRowNotTracked( const SwCursor& rCursor, const SvxPrintItem &rNew ) +{ + SwTableNode* pTableNd = rCursor.GetPoint()->nNode.GetNode().FindTableNode(); + if( !pTableNd ) + return; + + std::vector<SwTableLine*> aRowArr; // For Lines collecting + ::lcl_CollectLines( aRowArr, rCursor, true ); + + if( aRowArr.empty() ) + return; + + if (GetIDocumentUndoRedo().DoesUndo()) + { + GetIDocumentUndoRedo().AppendUndo(std::make_unique<SwUndoAttrTable>(*pTableNd)); + } + + std::vector<std::unique_ptr<SwTableFormatCmp>> aFormatCmp; + aFormatCmp.reserve( std::max( 255, static_cast<int>(aRowArr.size()) ) ); + + for( auto pLn : aRowArr ) + ::lcl_ProcessRowAttr( aFormatCmp, pLn, rNew ); + + getIDocumentState().SetModified(); +} + static void InsertCell( std::vector<SwCellFrame*>& rCellArr, SwCellFrame* pCellFrame ) { if( rCellArr.end() == std::find( rCellArr.begin(), rCellArr.end(), pCellFrame ) ) diff --git a/sw/source/core/frmedt/fetab.cxx b/sw/source/core/frmedt/fetab.cxx index 1a44707f43c3..bf7f1d2d618e 100644 --- a/sw/source/core/frmedt/fetab.cxx +++ b/sw/source/core/frmedt/fetab.cxx @@ -32,7 +32,9 @@ #include <fmtornt.hxx> #include <frmatr.hxx> #include <fesh.hxx> +#include <wrtsh.hxx> #include <doc.hxx> +#include <docsh.hxx> #include <IDocumentState.hxx> #include <IDocumentLayoutAccess.hxx> #include <cntfrm.hxx> @@ -325,6 +327,34 @@ bool SwFEShell::DeleteRow(bool bCompleteTable) } CurrShell aCurr( this ); + + // tracked deletion: remove only textbox content, + // and set IsNoTracked table line property to false + if ( GetDoc()->GetDocShell()->IsChangeRecording() ) + { + StartUndo(bCompleteTable ? SwUndoId::UI_TABLE_DELETE : SwUndoId::ROW_DELETE); + StartAllAction(); + + SvxPrintItem aNotTracked(RES_PRINT, false); + GetDoc()->SetRowNotTracked( *getShellCursor( false ), aNotTracked ); + + if ( SwWrtShell* pWrtShell = dynamic_cast<SwWrtShell*>(this) ) + pWrtShell->SelectTableRow(); + + SwEditShell* pEditShell = GetDoc()->GetEditShell(); + SwRedlineTable::size_type nPrev = pEditShell->GetRedlineCount(); + pEditShell->Delete(); + + EndAllActionAndCall(); + EndUndo(bCompleteTable ? SwUndoId::UI_TABLE_DELETE : SwUndoId::ROW_DELETE); + + // track row deletion only if there were tracked text changes + // FIXME redline count can be the same in special cases, e.g. adding a + // new tracked deletion with removing an own tracked insertion... + if ( nPrev != pEditShell->GetRedlineCount() ) + return true; + } + StartAllAction(); // search for boxes via the layout diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx index 65f39748fd34..fda4da0b85d9 100644 --- a/sw/source/core/table/swtable.cxx +++ b/sw/source/core/table/swtable.cxx @@ -1868,6 +1868,21 @@ sal_uLong SwTableBox::GetSttIdx() const return m_pStartNode ? m_pStartNode->GetIndex() : 0; } +bool SwTableBox::IsEmpty() const +{ + const SwStartNode *pSttNd = GetSttNd(); + if( pSttNd && + pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() ) + { + const SwContentNode *pCNd = + pSttNd->GetNodes()[pSttNd->GetIndex()+1]->GetContentNode(); + if( pCNd && !pCNd->Len() ) + return true; + } + + return false; +} + // retrieve information from the client bool SwTable::GetInfo( SfxPoolItem& rInfo ) const { diff --git a/sw/source/core/unocore/unomap.cxx b/sw/source/core/unocore/unomap.cxx index 247f3d84ece5..55b948a1eafe 100644 --- a/sw/source/core/unocore/unomap.cxx +++ b/sw/source/core/unocore/unomap.cxx @@ -542,6 +542,7 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s { u"" UNO_NAME_SIZE_TYPE, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_SIZE_TYPE }, { u"" UNO_NAME_WIDTH_TYPE, RES_FRM_SIZE, cppu::UnoType<sal_Int16>::get() , PROPERTY_NONE, MID_FRMSIZE_WIDTH_TYPE }, { u"" UNO_NAME_IS_SPLIT_ALLOWED, RES_ROW_SPLIT, cppu::UnoType<bool>::get() , PropertyAttribute::MAYBEVOID, 0}, + { u"" UNO_NAME_IS_NOT_TRACKED, RES_PRINT, cppu::UnoType<bool>::get() , PropertyAttribute::MAYBEVOID, 0}, { u"" UNO_NAME_ROW_INTEROP_GRAB_BAG, RES_FRMATR_GRABBAG, cppu::UnoType< cppu::UnoSequenceType<css::beans::PropertyValue> >::get(), PROPERTY_NONE, 0 }, { u"", 0, css::uno::Type(), 0, 0 } }; diff --git a/sw/source/filter/html/htmltab.cxx b/sw/source/filter/html/htmltab.cxx index b56a016e8d74..5149640c6bdd 100644 --- a/sw/source/filter/html/htmltab.cxx +++ b/sw/source/filter/html/htmltab.cxx @@ -1226,21 +1226,6 @@ const SwStartNode* HTMLTable::GetPrevBoxStartNode( sal_uInt16 nRow, sal_uInt16 n return pTable->GetPrevBoxStartNode(USHRT_MAX, USHRT_MAX); } -static bool IsBoxEmpty( const SwTableBox *pBox ) -{ - const SwStartNode *pSttNd = pBox->GetSttNd(); - if( pSttNd && - pSttNd->GetIndex() + 2 == pSttNd->EndOfSectionIndex() ) - { - const SwContentNode *pCNd = - pSttNd->GetNodes()[pSttNd->GetIndex()+1]->GetContentNode(); - if( pCNd && !pCNd->Len() ) - return true; - } - - return false; -} - sal_uInt16 HTMLTable::GetTopCellSpace( sal_uInt16 nRow ) const { sal_uInt16 nSpace = m_nCellPadding; @@ -1413,7 +1398,7 @@ void HTMLTable::FixFrameFormat( SwTableBox *pBox, pFrameFormat->ResetFormatAttr( RES_BACKGROUND ); // Only set format if there's a value or the box is empty - if( bHasNumFormat && (bHasValue || IsBoxEmpty(pBox)) ) + if( bHasNumFormat && (bHasValue || pBox->IsEmpty()) ) { bool bLock = pFrameFormat->GetDoc()->GetNumberFormatter() ->IsTextFormat( nNumFormat ); |