1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
20 #include <IDocumentFieldsAccess.hxx>
21 #include <IDocumentUndoRedo.hxx>
24 #include <swtable.hxx>
26 #include <swtblfmt.hxx>
27 #include <cellatr.hxx>
29 #include <swddetbl.hxx>
30 #include <ndindex.hxx>
31 #include <frameformats.hxx>
33 #include <osl/diagnose.h>
34 #include <svl/numformat.hxx>
38 #define CHECK_TABLE(t) (t).CheckConsistency();
40 #define CHECK_TABLE(t)
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
;
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();
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();
118 static bool lcl_SrchNew( const MapTableFrameFormat
& rMap
, SwFrameFormat
** pPara
)
120 if( rMap
.pOld
!= *pPara
)
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
) ) )
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();
188 pNewBox
= new SwTableBox(pBoxFormat
, nLines
, pCT
->m_pInsLine
);
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
);
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
) ) )
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
232 pCT
->m_pInsBox
->GetTabLines().push_back(pNewLine
);
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() )
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();
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
);
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
);
333 pDDEType
->IncRefCnt();
335 CHECK_TABLE( GetTable() );
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
);
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: */