summaryrefslogtreecommitdiffstats
path: root/sw/source/core/docnode/ndcopy.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/docnode/ndcopy.cxx')
-rw-r--r--sw/source/core/docnode/ndcopy.cxx378
1 files changed, 378 insertions, 0 deletions
diff --git a/sw/source/core/docnode/ndcopy.cxx b/sw/source/core/docnode/ndcopy.cxx
new file mode 100644
index 000000000..4b26acc0e
--- /dev/null
+++ b/sw/source/core/docnode/ndcopy.cxx
@@ -0,0 +1,378 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <doc.hxx>
+#include <IDocumentFieldsAccess.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <node.hxx>
+#include <frmfmt.hxx>
+#include <swtable.hxx>
+#include <ndtxt.hxx>
+#include <swtblfmt.hxx>
+#include <cellatr.hxx>
+#include <ddefld.hxx>
+#include <swddetbl.hxx>
+#include <ndindex.hxx>
+#include <frameformats.hxx>
+#include <vector>
+#include <osl/diagnose.h>
+#include <svl/numformat.hxx>
+
+
+#ifdef DBG_UTIL
+#define CHECK_TABLE(t) (t).CheckConsistency();
+#else
+#define CHECK_TABLE(t)
+#endif
+
+namespace {
+
+// Structure for the mapping from old and new frame formats to the
+// boxes and lines of a table
+struct MapTableFrameFormat
+{
+ const SwFrameFormat *pOld;
+ SwFrameFormat *pNew;
+ MapTableFrameFormat( const SwFrameFormat *pOldFormat, SwFrameFormat*pNewFormat )
+ : pOld( pOldFormat ), pNew( pNewFormat )
+ {}
+};
+
+}
+
+typedef std::vector<MapTableFrameFormat> MapTableFrameFormats;
+
+SwContentNode* SwTextNode::MakeCopy(SwDoc& rDoc, const SwNodeIndex& rIdx, bool const bNewFrames) const
+{
+ // the Copy-Textnode is the Node with the Text, the Copy-Attrnode is the
+ // node with the collection and hard attributes. Normally is the same
+ // node, but if insert a glossary without formatting, then the Attrnode
+ // is the prev node of the destination position in dest. document.
+ SwTextNode* pCpyTextNd = const_cast<SwTextNode*>(this);
+ SwTextNode* pCpyAttrNd = pCpyTextNd;
+
+ // Copy the formats to the other document
+ SwTextFormatColl* pColl = nullptr;
+ if( rDoc.IsInsOnlyTextGlossary() )
+ {
+ SwNodeIndex aIdx( rIdx, -1 );
+ if( aIdx.GetNode().IsTextNode() )
+ {
+ pCpyAttrNd = aIdx.GetNode().GetTextNode();
+ pColl = &pCpyAttrNd->GetTextColl()->GetNextTextFormatColl();
+ }
+ }
+ if( !pColl )
+ pColl = rDoc.CopyTextColl( *GetTextColl() );
+
+ SwTextNode* pTextNd = rDoc.GetNodes().MakeTextNode(rIdx, pColl, bNewFrames);
+
+ // METADATA: register copy
+ pTextNd->RegisterAsCopyOf(*pCpyTextNd);
+
+ // Copy Attribute/Text
+ if( !pCpyAttrNd->HasSwAttrSet() )
+ // An AttrSet was added for numbering, so delete it
+ pTextNd->ResetAllAttr();
+
+ // if Copy-Textnode unequal to Copy-Attrnode, then copy first
+ // the attributes into the new Node.
+ if( pCpyAttrNd != pCpyTextNd )
+ {
+ pCpyAttrNd->CopyAttr( pTextNd, 0, 0 );
+ if( pCpyAttrNd->HasSwAttrSet() )
+ {
+ SwAttrSet aSet( *pCpyAttrNd->GetpSwAttrSet() );
+ aSet.ClearItem( RES_PAGEDESC );
+ aSet.ClearItem( RES_BREAK );
+ aSet.CopyToModify( *pTextNd );
+ }
+ }
+
+ // Is that enough? What about PostIts/Fields/FieldTypes?
+ // #i96213# - force copy of all attributes
+ pCpyTextNd->CopyText( pTextNd, SwIndex( pCpyTextNd ),
+ pCpyTextNd->GetText().getLength(), true );
+
+ if( RES_CONDTXTFMTCOLL == pColl->Which() )
+ pTextNd->ChkCondColl();
+
+ return pTextNd;
+}
+
+static bool lcl_SrchNew( const MapTableFrameFormat& rMap, SwFrameFormat** pPara )
+{
+ if( rMap.pOld != *pPara )
+ return true;
+ *pPara = rMap.pNew;
+ return false;
+}
+
+namespace {
+
+struct CopyTable
+{
+ SwDoc& m_rDoc;
+ SwNodeOffset m_nOldTableSttIdx;
+ MapTableFrameFormats& m_rMapArr;
+ SwTableLine* m_pInsLine;
+ SwTableBox* m_pInsBox;
+ SwTableNode *m_pTableNd;
+ const SwTable *m_pOldTable;
+
+ CopyTable(SwDoc& rDc, MapTableFrameFormats& rArr, SwNodeOffset nOldStt,
+ SwTableNode& rTableNd, const SwTable* pOldTable)
+ : m_rDoc(rDc), m_nOldTableSttIdx(nOldStt), m_rMapArr(rArr),
+ m_pInsLine(nullptr), m_pInsBox(nullptr), m_pTableNd(&rTableNd), m_pOldTable(pOldTable)
+ {}
+};
+
+}
+
+static void lcl_CopyTableLine( const SwTableLine* pLine, CopyTable* pCT );
+
+static void lcl_CopyTableBox( SwTableBox* pBox, CopyTable* pCT )
+{
+ SwTableBoxFormat * pBoxFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
+ for (const auto& rMap : pCT->m_rMapArr)
+ if ( !lcl_SrchNew( rMap, reinterpret_cast<SwFrameFormat**>(&pBoxFormat) ) )
+ break;
+
+ if (pBoxFormat == pBox->GetFrameFormat()) // Create a new one?
+ {
+ const SwTableBoxFormula* pFormulaItem = pBoxFormat->GetItemIfSet( RES_BOXATR_FORMULA, false );
+ if( pFormulaItem && pFormulaItem->IsIntrnlName() )
+ {
+ const_cast<SwTableBoxFormula*>(pFormulaItem)->PtrToBoxNm(pCT->m_pOldTable);
+ }
+
+ pBoxFormat = pCT->m_rDoc.MakeTableBoxFormat();
+ pBoxFormat->CopyAttrs( *pBox->GetFrameFormat() );
+
+ if( pBox->GetSttIdx() )
+ {
+ SvNumberFormatter* pN = pCT->m_rDoc.GetNumberFormatter(false);
+ const SwTableBoxNumFormat* pFormatItem;
+ if( pN && pN->HasMergeFormatTable() &&
+ (pFormatItem = pBoxFormat->GetItemIfSet( RES_BOXATR_FORMAT, false )) )
+ {
+ sal_uLong nOldIdx = pFormatItem->GetValue();
+ sal_uLong nNewIdx = pN->GetMergeFormatIndex( nOldIdx );
+ if( nNewIdx != nOldIdx )
+ pBoxFormat->SetFormatAttr( SwTableBoxNumFormat( nNewIdx ));
+
+ }
+ }
+
+ pCT->m_rMapArr.emplace_back(pBox->GetFrameFormat(), pBoxFormat);
+ }
+
+ sal_uInt16 nLines = pBox->GetTabLines().size();
+ SwTableBox* pNewBox;
+ if( nLines )
+ pNewBox = new SwTableBox(pBoxFormat, nLines, pCT->m_pInsLine);
+ else
+ {
+ SwNodeIndex aNewIdx(*pCT->m_pTableNd, pBox->GetSttIdx() - pCT->m_nOldTableSttIdx);
+ assert(aNewIdx.GetNode().IsStartNode() && "Index is not on the start node");
+
+ pNewBox = new SwTableBox(pBoxFormat, aNewIdx, pCT->m_pInsLine);
+ pNewBox->setRowSpan( pBox->getRowSpan() );
+ }
+
+ pCT->m_pInsLine->GetTabBoxes().push_back( pNewBox );
+
+ if (nLines)
+ {
+ CopyTable aPara(*pCT);
+ aPara.m_pInsBox = pNewBox;
+ for( const SwTableLine* pLine : pBox->GetTabLines() )
+ lcl_CopyTableLine( pLine, &aPara );
+ }
+ else if (pNewBox->IsInHeadline(&pCT->m_pTableNd->GetTable()))
+ {
+ // In the headline, the paragraphs must match conditional styles
+ pNewBox->GetSttNd()->CheckSectionCondColl();
+ }
+}
+
+static void lcl_CopyTableLine( const SwTableLine* pLine, CopyTable* pCT )
+{
+ SwTableLineFormat * pLineFormat = static_cast<SwTableLineFormat*>(pLine->GetFrameFormat());
+ for (const auto& rMap : pCT->m_rMapArr)
+ if ( !lcl_SrchNew( rMap, reinterpret_cast<SwFrameFormat**>(&pLineFormat) ) )
+ break;
+
+ if( pLineFormat == pLine->GetFrameFormat() ) // Create a new one?
+ {
+ pLineFormat = pCT->m_rDoc.MakeTableLineFormat();
+ pLineFormat->CopyAttrs( *pLine->GetFrameFormat() );
+ pCT->m_rMapArr.emplace_back(pLine->GetFrameFormat(), pLineFormat);
+ }
+
+ SwTableLine* pNewLine = new SwTableLine(pLineFormat, pLine->GetTabBoxes().size(), pCT->m_pInsBox);
+ // Insert the new row into the table
+ if (pCT->m_pInsBox)
+ {
+ pCT->m_pInsBox->GetTabLines().push_back(pNewLine);
+ }
+ else
+ {
+ pCT->m_pTableNd->GetTable().GetTabLines().push_back(pNewLine);
+ }
+
+ pCT->m_pInsLine = pNewLine;
+ for( auto& rpBox : const_cast<SwTableLine*>(pLine)->GetTabBoxes() )
+ lcl_CopyTableBox(rpBox, pCT);
+}
+
+SwTableNode* SwTableNode::MakeCopy( SwDoc& rDoc, const SwNodeIndex& rIdx ) const
+{
+ // In which array are we? Nodes? UndoNodes?
+ SwNodes& rNds = const_cast<SwNodes&>(GetNodes());
+
+ {
+ if( rIdx < rDoc.GetNodes().GetEndOfInserts().GetIndex() &&
+ rIdx >= rDoc.GetNodes().GetEndOfInserts().StartOfSectionIndex() )
+ return nullptr;
+ }
+
+ // Copy the TableFrameFormat
+ OUString sTableName( GetTable().GetFrameFormat()->GetName() );
+ if( !rDoc.IsCopyIsMove() )
+ {
+ const SwFrameFormats& rTableFormats = *rDoc.GetTableFrameFormats();
+ for( size_t n = rTableFormats.size(); n; )
+ if( rTableFormats[ --n ]->GetName() == sTableName )
+ {
+ sTableName = rDoc.GetUniqueTableName();
+ break;
+ }
+ }
+
+ SwFrameFormat* pTableFormat = rDoc.MakeTableFrameFormat( sTableName, rDoc.GetDfltFrameFormat() );
+ pTableFormat->CopyAttrs( *GetTable().GetFrameFormat() );
+ SwTableNode* pTableNd = new SwTableNode( rIdx );
+ SwEndNode* pEndNd = new SwEndNode( rIdx, *pTableNd );
+ SwNodeIndex aInsPos( *pEndNd );
+
+ SwTable& rTable = pTableNd->GetTable();
+ rTable.SetTableStyleName(GetTable().GetTableStyleName());
+ rTable.RegisterToFormat( *pTableFormat );
+
+ rTable.SetRowsToRepeat( GetTable().GetRowsToRepeat() );
+ rTable.SetTableChgMode( GetTable().GetTableChgMode() );
+ rTable.SetTableModel( GetTable().IsNewModel() );
+
+ SwDDEFieldType* pDDEType = nullptr;
+ if( auto pSwDDETable = dynamic_cast<const SwDDETable*>( &GetTable() ) )
+ {
+ // We're copying a DDE table
+ // Is the field type available in the new document?
+ pDDEType = const_cast<SwDDETable*>(pSwDDETable)->GetDDEFieldType();
+ if( pDDEType->IsDeleted() )
+ rDoc.getIDocumentFieldsAccess().InsDeletedFieldType( *pDDEType );
+ else
+ pDDEType = static_cast<SwDDEFieldType*>(rDoc.getIDocumentFieldsAccess().InsertFieldType( *pDDEType ));
+ OSL_ENSURE( pDDEType, "unknown FieldType" );
+
+ // Swap the table pointers in the node
+ std::unique_ptr<SwDDETable> pNewTable(new SwDDETable( pTableNd->GetTable(), pDDEType ));
+ pTableNd->SetNewTable( std::move(pNewTable), false );
+ }
+ // First copy the content of the tables, we will later assign the
+ // boxes/lines and create the frames
+ SwNodeRange aRg( *this, SwNodeOffset(+1), *EndOfSectionNode() );
+
+ // If there is a table in this table, the table format for the outer table
+ // does not seem to be used, because the table does not have any contents yet
+ // (see IsUsed). Therefore the inner table gets the same name as the outer table.
+ // We have to make sure that the table node of the SwTable is accessible, even
+ // without any content in m_TabSortContentBoxes. #i26629#
+ pTableNd->GetTable().SetTableNode( pTableNd );
+ rNds.Copy_( aRg, aInsPos, false );
+ pTableNd->GetTable().SetTableNode( nullptr );
+
+ // Special case for a single box
+ if( 1 == GetTable().GetTabSortBoxes().size() )
+ {
+ aRg.aStart.Assign( *pTableNd, 1 );
+ aRg.aEnd.Assign( *pTableNd->EndOfSectionNode() );
+ rDoc.GetNodes().SectionDown( &aRg, SwTableBoxStartNode );
+ }
+
+ // Delete all frames from the copied area, they will be created
+ // during the generation of the table frame
+ pTableNd->DelFrames();
+
+ MapTableFrameFormats aMapArr;
+ CopyTable aPara( rDoc, aMapArr, GetIndex(), *pTableNd, &GetTable() );
+
+ for( const SwTableLine* pLine : GetTable().GetTabLines() )
+ lcl_CopyTableLine( pLine, &aPara );
+
+ if( pDDEType )
+ pDDEType->IncRefCnt();
+
+ CHECK_TABLE( GetTable() );
+ return pTableNd;
+}
+
+void SwTextNode::CopyCollFormat(SwTextNode& rDestNd, bool const bUndoForChgFormatColl)
+{
+ // Copy the formats into the other document:
+ // Special case for PageBreak/PageDesc/ColBrk
+ SwDoc& rDestDoc = rDestNd.GetDoc();
+ SwAttrSet aPgBrkSet( rDestDoc.GetAttrPool(), aBreakSetRange );
+ const SwAttrSet* pSet;
+
+ pSet = rDestNd.GetpSwAttrSet();
+ if( nullptr != pSet )
+ {
+ // Special cases for Break-Attributes
+ const SfxPoolItem* pAttr;
+ if( SfxItemState::SET == pSet->GetItemState( RES_BREAK, false, &pAttr ) )
+ aPgBrkSet.Put( *pAttr );
+
+ if( SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC, false, &pAttr ) )
+ aPgBrkSet.Put( *pAttr );
+ }
+
+ // this may create undo action SwUndoFormatCreate
+ auto const pCopy( rDestDoc.CopyTextColl( *GetTextColl() ) );
+ if (bUndoForChgFormatColl)
+ {
+ rDestNd.ChgFormatColl(pCopy);
+ }
+ else // tdf#138897
+ {
+ ::sw::UndoGuard const ug(rDestDoc.GetIDocumentUndoRedo());
+ rDestNd.ChgFormatColl(pCopy);
+ }
+ pSet = GetpSwAttrSet();
+ if( nullptr != pSet )
+ {
+ // note: this may create undo actions but not for setting the items
+ pSet->CopyToModify( rDestNd );
+ }
+
+ if( aPgBrkSet.Count() )
+ rDestNd.SetAttr( aPgBrkSet );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */