Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 : #include <doc.hxx>
20 : #include <IDocumentFieldsAccess.hxx>
21 : #include <node.hxx>
22 : #include <frmfmt.hxx>
23 : #include <swtable.hxx>
24 : #include <ndtxt.hxx>
25 : #include <swtblfmt.hxx>
26 : #include <cellatr.hxx>
27 : #include <docary.hxx>
28 : #include <ddefld.hxx>
29 : #include <swddetbl.hxx>
30 : #include <svtools/fmtfield.hxx>
31 : #include <vector>
32 :
33 :
34 : #ifdef DBG_UTIL
35 : #define CHECK_TABLE(t) (t).CheckConsistency();
36 : #else
37 : #define CHECK_TABLE(t)
38 : #endif
39 :
40 :
41 :
42 : // Structure for the mapping from old and new frame formats to the
43 : // boxes and lines of a table
44 : struct _MapTableFrameFormat
45 : {
46 : const SwFrameFormat *pOld;
47 : SwFrameFormat *pNew;
48 1354 : _MapTableFrameFormat( const SwFrameFormat *pOldFormat, SwFrameFormat*pNewFormat )
49 1354 : : pOld( pOldFormat ), pNew( pNewFormat )
50 1354 : {}
51 : };
52 :
53 : typedef std::vector<_MapTableFrameFormat> _MapTableFrameFormats;
54 :
55 6914 : SwContentNode* SwTextNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
56 : {
57 : // the Copy-Textnode is the Node with the Text, the Copy-Attrnode is the
58 : // node with the collection and hard attributes. Normally is the same
59 : // node, but if insert a glossary without formatting, then the Attrnode
60 : // is the prev node of the destionation position in dest. document.
61 6914 : SwTextNode* pCpyTextNd = const_cast<SwTextNode*>(this);
62 6914 : SwTextNode* pCpyAttrNd = pCpyTextNd;
63 :
64 : // Copy the formats to the other document
65 6914 : SwTextFormatColl* pColl = 0;
66 6914 : if( pDoc->IsInsOnlyTextGlossary() )
67 : {
68 2 : SwNodeIndex aIdx( rIdx, -1 );
69 2 : if( aIdx.GetNode().IsTextNode() )
70 : {
71 2 : pCpyAttrNd = aIdx.GetNode().GetTextNode();
72 2 : pColl = &pCpyAttrNd->GetTextColl()->GetNextTextFormatColl();
73 2 : }
74 : }
75 6914 : if( !pColl )
76 6912 : pColl = pDoc->CopyTextColl( *GetTextColl() );
77 :
78 6914 : SwTextNode* pTextNd = pDoc->GetNodes().MakeTextNode( rIdx, pColl );
79 :
80 : // METADATA: register copy
81 6914 : pTextNd->RegisterAsCopyOf(*pCpyTextNd);
82 :
83 : // Copy Attribute/Text
84 6914 : if( !pCpyAttrNd->HasSwAttrSet() )
85 : // An AttrSet was added for numbering, so delete it
86 4213 : pTextNd->ResetAllAttr();
87 :
88 : // if Copy-Textnode unequal to Copy-Attrnode, then copy first
89 : // the attributes into the new Node.
90 6914 : if( pCpyAttrNd != pCpyTextNd )
91 : {
92 2 : pCpyAttrNd->CopyAttr( pTextNd, 0, 0 );
93 2 : if( pCpyAttrNd->HasSwAttrSet() )
94 : {
95 0 : SwAttrSet aSet( *pCpyAttrNd->GetpSwAttrSet() );
96 0 : aSet.ClearItem( RES_PAGEDESC );
97 0 : aSet.ClearItem( RES_BREAK );
98 0 : aSet.CopyToModify( *pTextNd );
99 : }
100 : }
101 :
102 : // Is that enough? What about PostIts/Fields/FieldTypes?
103 : // #i96213# - force copy of all attributes
104 6914 : pCpyTextNd->CopyText( pTextNd, SwIndex( pCpyTextNd ),
105 13828 : pCpyTextNd->GetText().getLength(), true );
106 :
107 6914 : if( RES_CONDTXTFMTCOLL == pColl->Which() )
108 0 : pTextNd->ChkCondColl();
109 :
110 6914 : return pTextNd;
111 : }
112 :
113 5220 : static bool lcl_SrchNew( const _MapTableFrameFormat& rMap, SwFrameFormat** pPara )
114 : {
115 5220 : if( rMap.pOld != *pPara )
116 5207 : return true;
117 13 : *pPara = rMap.pNew;
118 13 : return false;
119 : }
120 :
121 : struct _CopyTable
122 : {
123 : SwDoc* m_pDoc;
124 : sal_uLong m_nOldTableSttIdx;
125 : _MapTableFrameFormats& m_rMapArr;
126 : SwTableLine* m_pInsLine;
127 : SwTableBox* m_pInsBox;
128 : SwTableNode *m_pTableNd;
129 : const SwTable *m_pOldTable;
130 :
131 284 : _CopyTable(SwDoc* pDc, _MapTableFrameFormats& rArr, sal_uLong nOldStt,
132 : SwTableNode& rTableNd, const SwTable* pOldTable)
133 : : m_pDoc(pDc), m_nOldTableSttIdx(nOldStt), m_rMapArr(rArr),
134 284 : m_pInsLine(0), m_pInsBox(0), m_pTableNd(&rTableNd), m_pOldTable(pOldTable)
135 284 : {}
136 : };
137 :
138 : static void lcl_CopyTableLine( const SwTableLine* pLine, _CopyTable* pCT );
139 :
140 979 : static void lcl_CopyTableBox( SwTableBox* pBox, _CopyTable* pCT )
141 : {
142 979 : SwTableBoxFormat * pBoxFormat = static_cast<SwTableBoxFormat*>(pBox->GetFrameFormat());
143 5272 : for (_MapTableFrameFormats::const_iterator it = pCT->m_rMapArr.begin(); it != pCT->m_rMapArr.end(); ++it)
144 4306 : if ( !lcl_SrchNew( *it, reinterpret_cast<SwFrameFormat**>(&pBoxFormat) ) )
145 13 : break;
146 :
147 979 : if (pBoxFormat == pBox->GetFrameFormat()) // Create a new one?
148 : {
149 : const SfxPoolItem* pItem;
150 966 : if( SfxItemState::SET == pBoxFormat->GetItemState( RES_BOXATR_FORMULA, false,
151 966 : &pItem ) && static_cast<const SwTableBoxFormula*>(pItem)->IsIntrnlName() )
152 : {
153 0 : const_cast<SwTableBoxFormula*>(static_cast<const SwTableBoxFormula*>(pItem))->PtrToBoxNm(pCT->m_pOldTable);
154 : }
155 :
156 966 : pBoxFormat = pCT->m_pDoc->MakeTableBoxFormat();
157 966 : pBoxFormat->CopyAttrs( *pBox->GetFrameFormat() );
158 :
159 966 : if( pBox->GetSttIdx() )
160 : {
161 966 : SvNumberFormatter* pN = pCT->m_pDoc->GetNumberFormatter(false);
162 966 : if( pN && pN->HasMergeFormatTable() && SfxItemState::SET == pBoxFormat->
163 0 : GetItemState( RES_BOXATR_FORMAT, false, &pItem ) )
164 : {
165 0 : sal_uLong nOldIdx = static_cast<const SwTableBoxNumFormat*>(pItem)->GetValue();
166 0 : sal_uLong nNewIdx = pN->GetMergeFormatIndex( nOldIdx );
167 0 : if( nNewIdx != nOldIdx )
168 0 : pBoxFormat->SetFormatAttr( SwTableBoxNumFormat( nNewIdx ));
169 :
170 : }
171 : }
172 :
173 966 : pCT->m_rMapArr.push_back(_MapTableFrameFormat(pBox->GetFrameFormat(), pBoxFormat));
174 : }
175 :
176 979 : sal_uInt16 nLines = pBox->GetTabLines().size();
177 : SwTableBox* pNewBox;
178 979 : if( nLines )
179 0 : pNewBox = new SwTableBox(pBoxFormat, nLines, pCT->m_pInsLine);
180 : else
181 : {
182 979 : SwNodeIndex aNewIdx(*pCT->m_pTableNd, pBox->GetSttIdx() - pCT->m_nOldTableSttIdx);
183 : OSL_ENSURE( aNewIdx.GetNode().IsStartNode(), "Index is not on the start node" );
184 :
185 979 : pNewBox = new SwTableBox(pBoxFormat, aNewIdx, pCT->m_pInsLine);
186 979 : pNewBox->setRowSpan( pBox->getRowSpan() );
187 : }
188 :
189 979 : pCT->m_pInsLine->GetTabBoxes().push_back( pNewBox );
190 :
191 979 : if (nLines)
192 : {
193 0 : _CopyTable aPara(*pCT);
194 0 : aPara.m_pInsBox = pNewBox;
195 0 : for( const SwTableLine* pLine : pBox->GetTabLines() )
196 0 : lcl_CopyTableLine( pLine, &aPara );
197 : }
198 979 : else if (pNewBox->IsInHeadline(&pCT->m_pTableNd->GetTable()))
199 : {
200 : // In the headline, the paragraphs must match conditional styles
201 668 : pNewBox->GetSttNd()->CheckSectionCondColl();
202 : }
203 979 : }
204 :
205 388 : static void lcl_CopyTableLine( const SwTableLine* pLine, _CopyTable* pCT )
206 : {
207 388 : SwTableLineFormat * pLineFormat = static_cast<SwTableLineFormat*>(pLine->GetFrameFormat());
208 1302 : for (_MapTableFrameFormats::const_iterator it = pCT->m_rMapArr.begin(); it != pCT->m_rMapArr.end(); ++it)
209 914 : if ( !lcl_SrchNew( *it, reinterpret_cast<SwFrameFormat**>(&pLineFormat) ) )
210 0 : break;
211 :
212 388 : if( pLineFormat == pLine->GetFrameFormat() ) // Create a new one?
213 : {
214 388 : pLineFormat = pCT->m_pDoc->MakeTableLineFormat();
215 388 : pLineFormat->CopyAttrs( *pLine->GetFrameFormat() );
216 388 : pCT->m_rMapArr.push_back(_MapTableFrameFormat(pLine->GetFrameFormat(), pLineFormat));
217 : }
218 :
219 388 : SwTableLine* pNewLine = new SwTableLine(pLineFormat, pLine->GetTabBoxes().size(), pCT->m_pInsBox);
220 : // Insert the new row into the table
221 388 : if (pCT->m_pInsBox)
222 : {
223 0 : pCT->m_pInsBox->GetTabLines().push_back(pNewLine);
224 : }
225 : else
226 : {
227 388 : pCT->m_pTableNd->GetTable().GetTabLines().push_back(pNewLine);
228 : }
229 :
230 388 : pCT->m_pInsLine = pNewLine;
231 4101 : for( SwTableBoxes::iterator it = const_cast<SwTableLine*>(pLine)->GetTabBoxes().begin();
232 2734 : it != const_cast<SwTableLine*>(pLine)->GetTabBoxes().end(); ++it)
233 979 : lcl_CopyTableBox(*it, pCT );
234 388 : }
235 :
236 284 : SwTableNode* SwTableNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
237 : {
238 : // In which array are we? Nodes? UndoNodes?
239 284 : SwNodes& rNds = (SwNodes&)GetNodes();
240 :
241 : {
242 284 : if( rIdx < pDoc->GetNodes().GetEndOfInserts().GetIndex() &&
243 0 : rIdx >= pDoc->GetNodes().GetEndOfInserts().StartOfSectionIndex() )
244 0 : return 0;
245 : }
246 :
247 : // Copy the TableFrameFormat
248 284 : OUString sTableName( GetTable().GetFrameFormat()->GetName() );
249 284 : if( !pDoc->IsCopyIsMove() )
250 : {
251 252 : const SwFrameFormats& rTableFormats = *pDoc->GetTableFrameFormats();
252 763 : for( size_t n = rTableFormats.size(); n; )
253 509 : if( rTableFormats[ --n ]->GetName() == sTableName )
254 : {
255 250 : sTableName = pDoc->GetUniqueTableName();
256 250 : break;
257 : }
258 : }
259 :
260 284 : SwFrameFormat* pTableFormat = pDoc->MakeTableFrameFormat( sTableName, pDoc->GetDfltFrameFormat() );
261 284 : pTableFormat->CopyAttrs( *GetTable().GetFrameFormat() );
262 284 : SwTableNode* pTableNd = new SwTableNode( rIdx );
263 284 : SwEndNode* pEndNd = new SwEndNode( rIdx, *pTableNd );
264 568 : SwNodeIndex aInsPos( *pEndNd );
265 :
266 284 : SwTable& rTable = (SwTable&)pTableNd->GetTable();
267 284 : rTable.RegisterToFormat( *pTableFormat );
268 :
269 284 : rTable.SetRowsToRepeat( GetTable().GetRowsToRepeat() );
270 284 : rTable.SetTableChgMode( GetTable().GetTableChgMode() );
271 284 : rTable.SetTableModel( GetTable().IsNewModel() );
272 :
273 284 : SwDDEFieldType* pDDEType = 0;
274 284 : if( IS_TYPE( SwDDETable, &GetTable() ))
275 : {
276 : // We're copying a DDE table
277 : // Is the field type available in the new document?
278 0 : pDDEType = const_cast<SwDDETable&>(static_cast<const SwDDETable&>(GetTable())).GetDDEFieldType();
279 0 : if( pDDEType->IsDeleted() )
280 0 : pDoc->getIDocumentFieldsAccess().InsDeletedFieldType( *pDDEType );
281 : else
282 0 : pDDEType = static_cast<SwDDEFieldType*>(pDoc->getIDocumentFieldsAccess().InsertFieldType( *pDDEType ));
283 : OSL_ENSURE( pDDEType, "unknown FieldType" );
284 :
285 : // Swap the table pointers in the node
286 0 : SwDDETable* pNewTable = new SwDDETable( pTableNd->GetTable(), pDDEType );
287 0 : pTableNd->SetNewTable( pNewTable, false );
288 : }
289 : // First copy the content of the tables, we will later assign the
290 : // boxes/lines and create the frames
291 568 : SwNodeRange aRg( *this, +1, *EndOfSectionNode() );
292 :
293 : // If there is a table in this table, the table format for the outer table
294 : // does not seem to be used, because the table does not have any contents yet
295 : // (see IsUsed). Therefore the inner table gets the same name as the outer table.
296 : // We have to make sure that the table node of the SwTable is accessible, even
297 : // without any content in m_TabSortContentBoxes. #i26629#
298 284 : pTableNd->GetTable().SetTableNode( pTableNd );
299 284 : rNds._Copy( aRg, aInsPos, false );
300 284 : pTableNd->GetTable().SetTableNode( 0 );
301 :
302 : // Special case for a single box
303 284 : if( 1 == GetTable().GetTabSortBoxes().size() )
304 : {
305 21 : aRg.aStart.Assign( *pTableNd, 1 );
306 21 : aRg.aEnd.Assign( *pTableNd->EndOfSectionNode() );
307 21 : pDoc->GetNodes().SectionDown( &aRg, SwTableBoxStartNode );
308 : }
309 :
310 : // Delete all frames from the copied area, they will be created
311 : // during the generation of the table frame
312 284 : pTableNd->DelFrms();
313 :
314 568 : _MapTableFrameFormats aMapArr;
315 284 : _CopyTable aPara( pDoc, aMapArr, GetIndex(), *pTableNd, &GetTable() );
316 :
317 672 : for( const SwTableLine* pLine : GetTable().GetTabLines() )
318 388 : lcl_CopyTableLine( pLine, &aPara );
319 :
320 284 : if( pDDEType )
321 0 : pDDEType->IncRefCnt();
322 :
323 : CHECK_TABLE( GetTable() );
324 568 : return pTableNd;
325 : }
326 :
327 291 : void SwTextNode::CopyCollFormat( SwTextNode& rDestNd )
328 : {
329 : // Copy the formats into the other document:
330 : // Special case for PageBreak/PageDesc/ColBrk
331 291 : SwDoc* pDestDoc = rDestNd.GetDoc();
332 291 : SwAttrSet aPgBrkSet( pDestDoc->GetAttrPool(), aBreakSetRange );
333 : const SwAttrSet* pSet;
334 :
335 291 : if( 0 != ( pSet = rDestNd.GetpSwAttrSet() ) )
336 : {
337 : // Special cases for Break-Attributes
338 : const SfxPoolItem* pAttr;
339 229 : if( SfxItemState::SET == pSet->GetItemState( RES_BREAK, false, &pAttr ) )
340 8 : aPgBrkSet.Put( *pAttr );
341 :
342 229 : if( SfxItemState::SET == pSet->GetItemState( RES_PAGEDESC, false, &pAttr ) )
343 0 : aPgBrkSet.Put( *pAttr );
344 : }
345 :
346 291 : rDestNd.ChgFormatColl( pDestDoc->CopyTextColl( *GetTextColl() ));
347 291 : if( 0 != ( pSet = GetpSwAttrSet() ) )
348 229 : pSet->CopyToModify( rDestNd );
349 :
350 291 : if( aPgBrkSet.Count() )
351 8 : rDestNd.SetAttr( aPgBrkSet );
352 468 : }
353 :
354 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|