summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sw/inc/swtable.hxx2
-rw-r--r--sw/qa/extras/uiwriter/uiwriter5.cxx49
-rw-r--r--sw/source/core/table/swtable.cxx31
-rw-r--r--sw/source/core/unocore/unocrsrhelper.cxx28
-rw-r--r--sw/source/filter/ww8/docxtableexport.cxx92
5 files changed, 161 insertions, 41 deletions
diff --git a/sw/inc/swtable.hxx b/sw/inc/swtable.hxx
index 0e01f1caecb5..77ec4163eb31 100644
--- a/sw/inc/swtable.hxx
+++ b/sw/inc/swtable.hxx
@@ -552,6 +552,8 @@ public:
sal_uInt16 nMaxStep ) const
{ return const_cast<SwTableBox*>(this)->FindEndOfRowSpan( rTable, nMaxStep ); }
void RegisterToFormat( SwFormat& rFormat ) ;
+ // get redline for the table cell, if it exists
+ SwRedlineTable::size_type GetRedline() const;
// get redline type
RedlineType GetRedlineType() const;
};
diff --git a/sw/qa/extras/uiwriter/uiwriter5.cxx b/sw/qa/extras/uiwriter/uiwriter5.cxx
index 4dd0a42d83c0..0bb6db185e37 100644
--- a/sw/qa/extras/uiwriter/uiwriter5.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter5.cxx
@@ -2641,6 +2641,55 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf150673_RedlineTableColumnDeletionWi
assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2);
}
+CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testRedlineTableColumnDeletionWithDOCXExport)
+{
+ // load a 1-row table, and delete the first column with enabled change tracking:
+ createSwDoc("tdf118311.fodt");
+ SwDoc* pDoc = getSwDoc();
+
+ // 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");
+ assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2);
+
+ // delete first table column with enabled change tracking
+ // (HasTextChangesOnly property of the cell will be false)
+ dispatchCommand(mxComponent, ".uno:DeleteColumns", {});
+
+ // Deleted text content with change tracking,
+ // but not table deletion
+ discardDumpedLayout();
+ pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "//page[1]//body/tab");
+ assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 2);
+
+ // Save it to a DOCX and load it back.
+ // Exporting change tracking of the cell wasn't supported.
+ // Also Manage Changes for the import.
+ reload("Office Open XML Text", "tdf79069_tracked_table_deletion.docx");
+ pDoc = getSwDoc();
+
+ // accept the deletion of the content of the first cell
+ SwEditShell* const pEditShell(pDoc->GetEditShell());
+ CPPUNIT_ASSERT_EQUAL(static_cast<SwRedlineTable::size_type>(1), pEditShell->GetRedlineCount());
+ pEditShell->AcceptRedline(0);
+
+ // table column was deleted
+ // (working export/import of HasTextChangesOnly of table cells)
+ pXmlDoc = parseLayoutDump();
+ assertXPath(pXmlDoc, "//page[1]//body/tab");
+ assertXPath(pXmlDoc, "//page[1]//body/tab/row/cell", 1);
+}
+
CPPUNIT_TEST_FIXTURE(SwUiWriterTest5, testTdf128335)
{
// Load the bugdoc, which has 3 textboxes.
diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx
index 83cb70fc0a65..8b2d395c05eb 100644
--- a/sw/source/core/table/swtable.cxx
+++ b/sw/source/core/table/swtable.cxx
@@ -2960,6 +2960,37 @@ void SwTableBox::ActualiseValueBox()
}
}
+SwRedlineTable::size_type SwTableBox::GetRedline() const
+{
+ const SwStartNode *pSttNd = GetSttNd();
+
+ if ( !pSttNd || GetRedlineType() == RedlineType::None )
+ return SwRedlineTable::npos;
+
+ SwPosition aCellStart( *GetSttNd(), SwNodeOffset(0) );
+ SwPosition aCellEnd( *GetSttNd()->EndOfSectionNode(), SwNodeOffset(-1) );
+ SwNodeIndex pEndNodeIndex(aCellEnd.GetNode());
+ const SwRedlineTable& aRedlineTable = GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
+ SwRedlineTable::size_type nRedlinePos = 0;
+ for( ; nRedlinePos < aRedlineTable.size(); ++nRedlinePos )
+ {
+ const SwRangeRedline* pRedline = aRedlineTable[ nRedlinePos ];
+
+ if ( pRedline->Start()->GetNodeIndex() > pEndNodeIndex.GetIndex() )
+ {
+ // no more redlines in the actual cell,
+ // check the next ones
+ break;
+ }
+
+ // redline in the cell
+ if ( aCellStart <= *pRedline->Start() )
+ return nRedlinePos;
+ }
+
+ return SwRedlineTable::npos;
+}
+
RedlineType SwTableBox::GetRedlineType() const
{
const SwRedlineTable& aRedlineTable = GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedlineTable();
diff --git a/sw/source/core/unocore/unocrsrhelper.cxx b/sw/source/core/unocore/unocrsrhelper.cxx
index 1e37c4015b1d..831cffd5ac1d 100644
--- a/sw/source/core/unocore/unocrsrhelper.cxx
+++ b/sw/source/core/unocore/unocrsrhelper.cxx
@@ -1497,7 +1497,8 @@ void makeTableCellRedline( SwTableBox& rTableBox,
std::u16string_view rRedlineType,
const uno::Sequence< beans::PropertyValue >& rRedlineProperties )
{
- IDocumentRedlineAccess* pRedlineAccess = &rTableBox.GetFrameFormat()->GetDoc()->getIDocumentRedlineAccess();
+ SwDoc* pDoc = rTableBox.GetFrameFormat()->GetDoc();
+ IDocumentRedlineAccess* pRedlineAccess = &pDoc->getIDocumentRedlineAccess();
RedlineType eType;
if ( rRedlineType == u"TableCellInsert" )
@@ -1513,6 +1514,31 @@ void makeTableCellRedline( SwTableBox& rTableBox,
throw lang::IllegalArgumentException();
}
+ // set table row property "HasTextChangesOnly" to false
+ // to handle tracked deletion or insertion of the table row on the UI
+ const SvxPrintItem *pHasTextChangesOnlyProp =
+ rTableBox.GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
+ if ( !pHasTextChangesOnlyProp || pHasTextChangesOnlyProp->GetValue() )
+ {
+ SvxPrintItem aSetTracking(RES_PRINT, false);
+ SwNodeIndex aInsPos( *rTableBox.GetSttNd(), 1 );
+ // as a workaround for the cells without text content,
+ // add a redline with invisible text CH_TXT_TRACKED_DUMMY_CHAR
+ if ( rTableBox.IsEmpty() )
+ {
+ SwPaM aPaM(aInsPos);
+ pDoc->getIDocumentContentOperations().InsertString( aPaM,
+ OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) );
+ aPaM.SetMark();
+ aPaM.GetMark()->SetContent(0);
+ makeRedline(aPaM, RedlineType::TableCellInsert == eType
+ ? u"Insert"
+ : u"Delete", rRedlineProperties);
+ }
+ SwCursor aCursor( SwPosition(aInsPos), nullptr );
+ pDoc->SetBoxAttr( aCursor, aSetTracking );
+ }
+
comphelper::SequenceAsHashMap aPropMap( rRedlineProperties );
std::size_t nAuthor = 0;
OUString sAuthor;
diff --git a/sw/source/filter/ww8/docxtableexport.cxx b/sw/source/filter/ww8/docxtableexport.cxx
index aa8697c2f150..51fb3540c9df 100644
--- a/sw/source/filter/ww8/docxtableexport.cxx
+++ b/sw/source/filter/ww8/docxtableexport.cxx
@@ -697,52 +697,64 @@ void DocxAttributeOutput::TableCellRedline(
bool bRemovePersonalInfo
= SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo);
- // search next Redline
- const SwExtraRedlineTable& aExtraRedlineTable
- = m_rExport.m_rDoc.getIDocumentRedlineAccess().GetExtraRedlineTable();
- for (sal_uInt16 nCurRedlinePos = 0; nCurRedlinePos < aExtraRedlineTable.GetSize();
- ++nCurRedlinePos)
+ // check table row property "HasTextChangesOnly"
+ SwRedlineTable::size_type nChange = pTabBox->GetRedline();
+ if (nChange != SwRedlineTable::npos)
{
- SwExtraRedline* pExtraRedline = aExtraRedlineTable.GetRedline(nCurRedlinePos);
- const SwTableCellRedline* pTableCellRedline
- = dynamic_cast<const SwTableCellRedline*>(pExtraRedline);
- if (pTableCellRedline && &pTableCellRedline->GetTableBox() == pTabBox)
+ const SwRedlineTable& aRedlineTable
+ = m_rExport.m_rDoc.getIDocumentRedlineAccess().GetRedlineTable();
+ const SwRangeRedline* pRedline = aRedlineTable[nChange];
+ SwTableCellRedline* pTableCellRedline = nullptr;
+ bool bIsInExtra = false;
+
+ // use the original DOCX redline data stored in ExtraRedlineTable,
+ // if it exists and its type wasn't changed
+ const SwExtraRedlineTable& aExtraRedlineTable
+ = m_rExport.m_rDoc.getIDocumentRedlineAccess().GetExtraRedlineTable();
+ for (sal_uInt16 nCurRedlinePos = 0; nCurRedlinePos < aExtraRedlineTable.GetSize();
+ ++nCurRedlinePos)
{
- // Redline for this table cell
- const SwRedlineData& aRedlineData = pTableCellRedline->GetRedlineData();
- RedlineType nRedlineType = aRedlineData.GetType();
- switch (nRedlineType)
+ SwExtraRedline* pExtraRedline = aExtraRedlineTable.GetRedline(nCurRedlinePos);
+ pTableCellRedline = dynamic_cast<SwTableCellRedline*>(pExtraRedline);
+ if (pTableCellRedline && &pTableCellRedline->GetTableBox() == pTabBox)
{
- case RedlineType::TableCellInsert:
- case RedlineType::TableCellDelete:
- {
- OString aId(OString::number(m_nRedlineId++));
- const OUString& rAuthor(SW_MOD()->GetRedlineAuthor(aRedlineData.GetAuthor()));
- OString aAuthor(OUStringToOString(
- bRemovePersonalInfo
- ? "Author" + OUString::number(GetExport().GetInfoID(rAuthor))
- : rAuthor,
- RTL_TEXTENCODING_UTF8));
-
- sal_Int32 nElement
- = nRedlineType == RedlineType::TableCellInsert ? XML_cellIns : XML_cellDel;
- const DateTime aDateTime = aRedlineData.GetTimeStamp();
- bool bNoDate = bRemovePersonalInfo
- || (aDateTime.GetYear() == 1970 && aDateTime.GetMonth() == 1
- && aDateTime.GetDay() == 1);
- if (bNoDate)
- m_pSerializer->singleElementNS(XML_w, nElement, FSNS(XML_w, XML_id), aId,
- FSNS(XML_w, XML_author), aAuthor);
- else
- m_pSerializer->singleElementNS(
- XML_w, nElement, FSNS(XML_w, XML_id), aId, FSNS(XML_w, XML_author),
- aAuthor, FSNS(XML_w, XML_date), DateTimeToOString(aDateTime));
- }
+ bIsInExtra = true;
break;
- default:
- break;
}
}
+
+ const SwRedlineData& aRedlineData
+ = bIsInExtra &&
+ // still the same type (an inserted cell could become a tracked deleted one)
+ pRedline->GetRedlineData().GetType() == pRedline->GetRedlineData().GetType()
+ ? pTableCellRedline->GetRedlineData()
+ : pRedline->GetRedlineData();
+
+ // Note: all redline ranges and table row redline (with the same author and timestamp)
+ // use the same redline id in OOXML exported by MSO, but it seems, the recent solution
+ // (different IDs for different ranges, also row changes) is also portable.
+ OString aId(OString::number(m_nRedlineId++));
+ const OUString& rAuthor(SW_MOD()->GetRedlineAuthor(aRedlineData.GetAuthor()));
+ OString aAuthor(OUStringToOString(
+ bRemovePersonalInfo ? "Author" + OUString::number(GetExport().GetInfoID(rAuthor))
+ : rAuthor,
+ RTL_TEXTENCODING_UTF8));
+
+ const DateTime aDateTime = aRedlineData.GetTimeStamp();
+ bool bNoDate = bRemovePersonalInfo
+ || (aDateTime.GetYear() == 1970 && aDateTime.GetMonth() == 1
+ && aDateTime.GetDay() == 1);
+
+ if (bNoDate)
+ m_pSerializer->singleElementNS(
+ XML_w, RedlineType::Delete == pRedline->GetType() ? XML_cellDel : XML_cellIns,
+ FSNS(XML_w, XML_id), aId, FSNS(XML_w, XML_author), aAuthor);
+ else
+ m_pSerializer->singleElementNS(
+ XML_w, RedlineType::Delete == pRedline->GetType() ? XML_cellDel : XML_cellIns,
+ FSNS(XML_w, XML_id), aId, FSNS(XML_w, XML_author), aAuthor, FSNS(XML_w, XML_date),
+ DateTimeToOString(aDateTime));
+ return;
}
}