Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / docnode / ndcopy.cxx
blob8a63949fa3c869d1d3411567a704ec2f4946bdf8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
19 #include <doc.hxx>
20 #include <IDocumentFieldsAccess.hxx>
21 #include <IDocumentUndoRedo.hxx>
22 #include <node.hxx>
23 #include <frmfmt.hxx>
24 #include <swtable.hxx>
25 #include <ndtxt.hxx>
26 #include <swtblfmt.hxx>
27 #include <cellatr.hxx>
28 #include <ddefld.hxx>
29 #include <swddetbl.hxx>
30 #include <ndindex.hxx>
31 #include <frameformats.hxx>
32 #include <vector>
33 #include <osl/diagnose.h>
34 #include <svl/numformat.hxx>
37 #ifdef DBG_UTIL
38 #define CHECK_TABLE(t) (t).CheckConsistency();
39 #else
40 #define CHECK_TABLE(t)
41 #endif
43 namespace {
45 // Structure for the mapping from old and new frame formats to the
46 // boxes and lines of a table
47 struct MapTableFrameFormat
49 const SwFrameFormat *pOld;
50 SwFrameFormat *pNew;
51 MapTableFrameFormat( const SwFrameFormat *pOldFormat, SwFrameFormat*pNewFormat )
52 : pOld( pOldFormat ), pNew( pNewFormat )
58 typedef std::vector<MapTableFrameFormat> MapTableFrameFormats;
60 SwContentNode* SwTextNode::MakeCopy(SwDoc& rDoc, SwNode& rIdx, bool const bNewFrames) const
62 // the Copy-Textnode is the Node with the Text, the Copy-Attrnode is the
63 // node with the collection and hard attributes. Normally is the same
64 // node, but if insert a glossary without formatting, then the Attrnode
65 // is the prev node of the destination position in dest. document.
66 SwTextNode* pCpyTextNd = const_cast<SwTextNode*>(this);
67 SwTextNode* pCpyAttrNd = pCpyTextNd;
69 // Copy the formats to the other document
70 SwTextFormatColl* pColl = nullptr;
71 if( rDoc.IsInsOnlyTextGlossary() )
73 SwNodeIndex aIdx( rIdx, -1 );
74 if( aIdx.GetNode().IsTextNode() )
76 pCpyAttrNd = aIdx.GetNode().GetTextNode();
77 pColl = &pCpyAttrNd->GetTextColl()->GetNextTextFormatColl();
80 if( !pColl )
81 pColl = rDoc.CopyTextColl( *GetTextColl() );
83 SwTextNode* pTextNd = rDoc.GetNodes().MakeTextNode(rIdx, pColl, bNewFrames);
85 // METADATA: register copy
86 pTextNd->RegisterAsCopyOf(*pCpyTextNd);
88 // Copy Attribute/Text
89 if( !pCpyAttrNd->HasSwAttrSet() )
90 // An AttrSet was added for numbering, so delete it
91 pTextNd->ResetAllAttr();
93 // if Copy-Textnode unequal to Copy-Attrnode, then copy first
94 // the attributes into the new Node.
95 if( pCpyAttrNd != pCpyTextNd )
97 pCpyAttrNd->CopyAttr( pTextNd, 0, 0 );
98 if( pCpyAttrNd->HasSwAttrSet() )
100 SwAttrSet aSet( *pCpyAttrNd->GetpSwAttrSet() );
101 aSet.ClearItem( RES_PAGEDESC );
102 aSet.ClearItem( RES_BREAK );
103 aSet.CopyToModify( *pTextNd );
107 // Is that enough? What about PostIts/Fields/FieldTypes?
108 // #i96213# - force copy of all attributes
109 pCpyTextNd->CopyText( pTextNd, SwContentIndex( pCpyTextNd ),
110 pCpyTextNd->GetText().getLength(), true );
112 if( RES_CONDTXTFMTCOLL == pColl->Which() )
113 pTextNd->ChkCondColl();
115 return pTextNd;
118 static bool lcl_SrchNew( const MapTableFrameFormat& rMap, SwFrameFormat** pPara )
120 if( rMap.pOld != *pPara )
121 return true;
122 *pPara = rMap.pNew;
123 return false;
126 namespace {
128 struct CopyTable
130 SwDoc& m_rDoc;
131 SwNodeOffset m_nOldTableSttIdx;
132 MapTableFrameFormats& m_rMapArr;
133 SwTableLine* m_pInsLine;
134 SwTableBox* m_pInsBox;
135 SwTableNode *m_pTableNd;
136 const SwTable *m_pOldTable;
138 CopyTable(SwDoc& rDc, MapTableFrameFormats& rArr, SwNodeOffset nOldStt,
139 SwTableNode& rTableNd, const SwTable* pOldTable)
140 : m_rDoc(rDc), m_nOldTableSttIdx(nOldStt), m_rMapArr(rArr),
141 m_pInsLine(nullptr), m_pInsBox(nullptr), m_pTableNd(&rTableNd), m_pOldTable(pOldTable)
147 static void lcl_CopyTableLine( const SwTableLine* pLine, CopyTable* pCT );
149 static void lcl_CopyTableBox( SwTableBox* pBox, CopyTable* pCT )
151 SwTableBoxFormat * pBoxFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
152 for (const auto& rMap : pCT->m_rMapArr)
153 if ( !lcl_SrchNew( rMap, reinterpret_cast<SwFrameFormat**>(&pBoxFormat) ) )
154 break;
156 if (pBoxFormat == pBox->GetFrameFormat()) // Create a new one?
158 const SwTableBoxFormula* pFormulaItem = pBoxFormat->GetItemIfSet( RES_BOXATR_FORMULA, false );
159 if( pFormulaItem && pFormulaItem->IsIntrnlName() )
161 const_cast<SwTableBoxFormula*>(pFormulaItem)->PtrToBoxNm(pCT->m_pOldTable);
164 pBoxFormat = pCT->m_rDoc.MakeTableBoxFormat();
165 pBoxFormat->CopyAttrs( *pBox->GetFrameFormat() );
167 if( pBox->GetSttIdx() )
169 SvNumberFormatter* pN = pCT->m_rDoc.GetNumberFormatter(false);
170 const SwTableBoxNumFormat* pFormatItem;
171 if( pN && pN->HasMergeFormatTable() &&
172 (pFormatItem = pBoxFormat->GetItemIfSet( RES_BOXATR_FORMAT, false )) )
174 sal_uLong nOldIdx = pFormatItem->GetValue();
175 sal_uLong nNewIdx = pN->GetMergeFormatIndex( nOldIdx );
176 if( nNewIdx != nOldIdx )
177 pBoxFormat->SetFormatAttr( SwTableBoxNumFormat( nNewIdx ));
182 pCT->m_rMapArr.emplace_back(pBox->GetFrameFormat(), pBoxFormat);
185 sal_uInt16 nLines = pBox->GetTabLines().size();
186 SwTableBox* pNewBox;
187 if( nLines )
188 pNewBox = new SwTableBox(pBoxFormat, nLines, pCT->m_pInsLine);
189 else
191 SwNodeIndex aNewIdx(*pCT->m_pTableNd, pBox->GetSttIdx() - pCT->m_nOldTableSttIdx);
192 assert(aNewIdx.GetNode().IsStartNode() && "Index is not on the start node");
194 pNewBox = new SwTableBox(pBoxFormat, aNewIdx, pCT->m_pInsLine);
195 pNewBox->setRowSpan( pBox->getRowSpan() );
198 pCT->m_pInsLine->GetTabBoxes().push_back( pNewBox );
200 if (nLines)
202 CopyTable aPara(*pCT);
203 aPara.m_pInsBox = pNewBox;
204 for( const SwTableLine* pLine : pBox->GetTabLines() )
205 lcl_CopyTableLine( pLine, &aPara );
207 else if (pNewBox->IsInHeadline(&pCT->m_pTableNd->GetTable()))
209 // In the headline, the paragraphs must match conditional styles
210 pNewBox->GetSttNd()->CheckSectionCondColl();
214 static void lcl_CopyTableLine( const SwTableLine* pLine, CopyTable* pCT )
216 SwTableLineFormat * pLineFormat = static_cast<SwTableLineFormat*>(pLine->GetFrameFormat());
217 for (const auto& rMap : pCT->m_rMapArr)
218 if ( !lcl_SrchNew( rMap, reinterpret_cast<SwFrameFormat**>(&pLineFormat) ) )
219 break;
221 if( pLineFormat == pLine->GetFrameFormat() ) // Create a new one?
223 pLineFormat = pCT->m_rDoc.MakeTableLineFormat();
224 pLineFormat->CopyAttrs( *pLine->GetFrameFormat() );
225 pCT->m_rMapArr.emplace_back(pLine->GetFrameFormat(), pLineFormat);
228 SwTableLine* pNewLine = new SwTableLine(pLineFormat, pLine->GetTabBoxes().size(), pCT->m_pInsBox);
229 // Insert the new row into the table
230 if (pCT->m_pInsBox)
232 pCT->m_pInsBox->GetTabLines().push_back(pNewLine);
234 else
236 pCT->m_pTableNd->GetTable().GetTabLines().push_back(pNewLine);
239 pCT->m_pInsLine = pNewLine;
240 for( auto& rpBox : const_cast<SwTableLine*>(pLine)->GetTabBoxes() )
241 lcl_CopyTableBox(rpBox, pCT);
244 SwTableNode* SwTableNode::MakeCopy( SwDoc& rDoc, const SwNodeIndex& rIdx ) const
246 // In which array are we? Nodes? UndoNodes?
247 SwNodes& rNds = const_cast<SwNodes&>(GetNodes());
250 if( rIdx < rDoc.GetNodes().GetEndOfInserts().GetIndex() &&
251 rIdx >= rDoc.GetNodes().GetEndOfInserts().StartOfSectionIndex() )
252 return nullptr;
255 // Copy the TableFrameFormat
256 OUString sTableName( GetTable().GetFrameFormat()->GetName() );
257 if( !rDoc.IsCopyIsMove() )
259 const sw::TableFrameFormats& rTableFormats = *rDoc.GetTableFrameFormats();
260 for( size_t n = rTableFormats.size(); n; )
262 const SwTableFormat* pFormat = rTableFormats[--n];
263 if (pFormat->GetName() == sTableName && rDoc.IsUsed(*pFormat))
265 sTableName = rDoc.GetUniqueTableName();
266 break;
271 SwFrameFormat* pTableFormat = rDoc.MakeTableFrameFormat( sTableName, rDoc.GetDfltFrameFormat() );
272 pTableFormat->CopyAttrs( *GetTable().GetFrameFormat() );
273 SwTableNode* pTableNd = new SwTableNode( rIdx.GetNode() );
274 SwEndNode* pEndNd = new SwEndNode( rIdx.GetNode(), *pTableNd );
275 SwNodeIndex aInsPos( *pEndNd );
277 SwTable& rTable = pTableNd->GetTable();
278 rTable.SetTableStyleName(GetTable().GetTableStyleName());
279 rTable.RegisterToFormat( *pTableFormat );
281 rTable.SetRowsToRepeat( GetTable().GetRowsToRepeat() );
282 rTable.SetTableChgMode( GetTable().GetTableChgMode() );
283 rTable.SetTableModel( GetTable().IsNewModel() );
285 SwDDEFieldType* pDDEType = nullptr;
286 if( auto pSwDDETable = dynamic_cast<const SwDDETable*>( &GetTable() ) )
288 // We're copying a DDE table
289 // Is the field type available in the new document?
290 pDDEType = const_cast<SwDDETable*>(pSwDDETable)->GetDDEFieldType();
291 if( pDDEType->IsDeleted() )
292 rDoc.getIDocumentFieldsAccess().InsDeletedFieldType( *pDDEType );
293 else
294 pDDEType = static_cast<SwDDEFieldType*>(rDoc.getIDocumentFieldsAccess().InsertFieldType( *pDDEType ));
295 OSL_ENSURE( pDDEType, "unknown FieldType" );
297 // Swap the table pointers in the node
298 std::unique_ptr<SwDDETable> pNewTable(new SwDDETable( pTableNd->GetTable(), pDDEType ));
299 pTableNd->SetNewTable( std::move(pNewTable), false );
301 // First copy the content of the tables, we will later assign the
302 // boxes/lines and create the frames
303 SwNodeRange aRg( *this, SwNodeOffset(+1), *EndOfSectionNode() );
305 // If there is a table in this table, the table format for the outer table
306 // does not seem to be used, because the table does not have any contents yet
307 // (see IsUsed). Therefore the inner table gets the same name as the outer table.
308 // We have to make sure that the table node of the SwTable is accessible, even
309 // without any content in m_TabSortContentBoxes. #i26629#
310 pTableNd->GetTable().SetTableNode( pTableNd );
311 rNds.Copy_( aRg, aInsPos.GetNode(), false );
312 pTableNd->GetTable().SetTableNode( nullptr );
314 // Special case for a single box
315 if( 1 == GetTable().GetTabSortBoxes().size() )
317 aRg.aStart.Assign( *pTableNd, 1 );
318 aRg.aEnd.Assign( *pTableNd->EndOfSectionNode() );
319 rDoc.GetNodes().SectionDown( &aRg, SwTableBoxStartNode );
322 // Delete all frames from the copied area, they will be created
323 // during the generation of the table frame
324 pTableNd->DelFrames();
326 MapTableFrameFormats aMapArr;
327 CopyTable aPara( rDoc, aMapArr, GetIndex(), *pTableNd, &GetTable() );
329 for( const SwTableLine* pLine : GetTable().GetTabLines() )
330 lcl_CopyTableLine( pLine, &aPara );
332 if( pDDEType )
333 pDDEType->IncRefCnt();
335 CHECK_TABLE( GetTable() );
336 return pTableNd;
339 void SwTextNode::CopyCollFormat(SwTextNode& rDestNd, bool const bUndoForChgFormatColl)
341 // Copy the formats into the other document:
342 // Special case for PageBreak/PageDesc/ColBrk
343 SwDoc& rDestDoc = rDestNd.GetDoc();
344 SwAttrSet aPgBrkSet( rDestDoc.GetAttrPool(), aBreakSetRange );
345 const SwAttrSet* pSet;
347 pSet = rDestNd.GetpSwAttrSet();
348 if( nullptr != pSet )
350 // Special cases for Break-Attributes
351 const SfxPoolItem* pAttr;
352 if( SfxItemState::SET == pSet->GetItemState( RES_BREAK, false, &pAttr ) )
353 aPgBrkSet.Put( *pAttr );
355 if( SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC, false, &pAttr ) )
356 aPgBrkSet.Put( *pAttr );
359 // this may create undo action SwUndoFormatCreate
360 auto const pCopy( rDestDoc.CopyTextColl( *GetTextColl() ) );
361 if (bUndoForChgFormatColl)
363 rDestNd.ChgFormatColl(pCopy);
365 else // tdf#138897
367 ::sw::UndoGuard const ug(rDestDoc.GetIDocumentUndoRedo());
368 rDestNd.ChgFormatColl(pCopy);
370 pSet = GetpSwAttrSet();
371 if( nullptr != pSet )
373 // note: this may create undo actions but not for setting the items
374 pSet->CopyToModify( rDestNd );
377 if( aPgBrkSet.Count() )
378 rDestNd.SetAttr( aPgBrkSet );
381 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */