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 :
20 :
21 : #include <editeng/brkitem.hxx>
22 :
23 : #include <hintids.hxx>
24 : #include <fmtpdsc.hxx>
25 : #include <fmtanchr.hxx>
26 : #include <fmtcntnt.hxx>
27 : #include <doc.hxx>
28 : #include <IDocumentUndoRedo.hxx>
29 : #include <pam.hxx>
30 : #include <ndtxt.hxx>
31 : #include <fldbas.hxx>
32 : #include <swtable.hxx>
33 : #include <ddefld.hxx>
34 : #include <undobj.hxx>
35 : #include <IMark.hxx>
36 : #include <mvsave.hxx>
37 : #include <cellatr.hxx>
38 : #include <swtblfmt.hxx>
39 : #include <swddetbl.hxx>
40 : #include <docary.hxx>
41 : #include <fmtcnct.hxx>
42 : #include <redline.hxx>
43 : #include <paratr.hxx>
44 : #include <pagedesc.hxx>
45 : #include <poolfmt.hxx>
46 : #include <SwNodeNum.hxx>
47 : #include <set>
48 : #include <vector>
49 : #include <boost/foreach.hpp>
50 :
51 : #ifdef DBG_UTIL
52 : #define CHECK_TABLE(t) (t).CheckConsistency();
53 : #else
54 : #define CHECK_TABLE(t)
55 : #endif
56 :
57 : namespace
58 : {
59 : /*
60 : The lcl_CopyBookmarks function has to copy bookmarks from the source to the destination nodes
61 : array. It is called after a call of the _CopyNodes(..) function. But this function does not copy
62 : every node (at least at the moment: 2/08/2006 ), section start and end nodes will not be copied if the corresponding end/start node is outside the copied pam.
63 : The lcl_NonCopyCount function counts the number of these nodes, given the copied pam and a node
64 : index inside the pam.
65 : rPam is the original source pam, rLastIdx is the last calculated position, rDelCount the number
66 : of "non-copy" nodes between rPam.Start() and rLastIdx.
67 : nNewIdx is the new position of interest.
68 : */
69 :
70 3 : static void lcl_NonCopyCount( const SwPaM& rPam, SwNodeIndex& rLastIdx, const sal_uLong nNewIdx, sal_uLong& rDelCount )
71 : {
72 3 : sal_uLong nStart = rPam.Start()->nNode.GetIndex();
73 3 : sal_uLong nEnd = rPam.End()->nNode.GetIndex();
74 3 : if( rLastIdx.GetIndex() < nNewIdx ) // Moving forward?
75 : {
76 6 : do // count "non-copy" nodes
77 : {
78 6 : SwNode& rNode = rLastIdx.GetNode();
79 13 : if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd )
80 7 : || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) )
81 0 : ++rDelCount;
82 6 : ++rLastIdx;
83 : }
84 6 : while( rLastIdx.GetIndex() < nNewIdx );
85 : }
86 0 : else if( rDelCount ) // optimization: if there are no "non-copy" nodes until now,
87 : // no move backward needed
88 : {
89 0 : while( rLastIdx.GetIndex() > nNewIdx )
90 : {
91 0 : SwNode& rNode = rLastIdx.GetNode();
92 0 : if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd )
93 0 : || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) )
94 0 : --rDelCount;
95 0 : rLastIdx--;
96 : }
97 : }
98 3 : }
99 :
100 3 : static void lcl_SetCpyPos( const SwPosition& rOrigPos,
101 : const SwPosition& rOrigStt,
102 : const SwPosition& rCpyStt,
103 : SwPosition& rChgPos,
104 : sal_uLong nDelCount )
105 : {
106 3 : sal_uLong nNdOff = rOrigPos.nNode.GetIndex();
107 3 : nNdOff -= rOrigStt.nNode.GetIndex();
108 3 : nNdOff -= nDelCount;
109 3 : xub_StrLen nCntntPos = rOrigPos.nContent.GetIndex();
110 :
111 : // Always adjust <nNode> at to be changed <SwPosition> instance <rChgPos>
112 3 : rChgPos.nNode = nNdOff + rCpyStt.nNode.GetIndex();
113 3 : if( !nNdOff )
114 : {
115 : // dann nur den Content anpassen
116 0 : if( nCntntPos > rOrigStt.nContent.GetIndex() )
117 0 : nCntntPos = nCntntPos - rOrigStt.nContent.GetIndex();
118 : else
119 0 : nCntntPos = 0;
120 0 : nCntntPos = nCntntPos + rCpyStt.nContent.GetIndex();
121 : }
122 3 : rChgPos.nContent.Assign( rChgPos.nNode.GetNode().GetCntntNode(), nCntntPos );
123 3 : }
124 :
125 : // TODO: use SaveBookmark (from _DelBookmarks)
126 17 : static void lcl_CopyBookmarks(const SwPaM& rPam, SwPaM& rCpyPam)
127 : {
128 17 : const SwDoc* pSrcDoc = rPam.GetDoc();
129 17 : SwDoc* pDestDoc = rCpyPam.GetDoc();
130 17 : const IDocumentMarkAccess* const pSrcMarkAccess = pSrcDoc->getIDocumentMarkAccess();
131 17 : ::sw::UndoGuard const undoGuard(pDestDoc->GetIDocumentUndoRedo());
132 :
133 17 : const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
134 17 : SwPosition* pCpyStt = rCpyPam.Start();
135 :
136 : typedef ::std::vector< const ::sw::mark::IMark* > mark_vector_t;
137 17 : mark_vector_t vMarksToCopy;
138 255 : for(IDocumentMarkAccess::const_iterator_t ppMark = pSrcMarkAccess->getMarksBegin();
139 170 : ppMark != pSrcMarkAccess->getMarksEnd();
140 : ++ppMark)
141 : {
142 68 : const ::sw::mark::IMark* const pMark = ppMark->get();
143 68 : const SwPosition& rMarkStart = pMark->GetMarkStart();
144 68 : const SwPosition& rMarkEnd = pMark->GetMarkEnd();
145 : // only include marks that are in the range and not touching
146 : // both start and end
147 68 : bool bIsNotOnBoundary = pMark->IsExpanded()
148 28 : ? (rMarkStart != rStt || rMarkEnd != rEnd) // rMarkStart != rMarkEnd
149 96 : : (rMarkStart != rStt && rMarkEnd != rEnd); // rMarkStart == rMarkEnd
150 68 : if(rMarkStart >= rStt && rMarkEnd <= rEnd && bIsNotOnBoundary)
151 : {
152 3 : vMarksToCopy.push_back(pMark);
153 : }
154 : }
155 : // We have to count the "non-copied" nodes..
156 17 : SwNodeIndex aCorrIdx(rStt.nNode);
157 17 : sal_uLong nDelCount = 0;
158 60 : for(mark_vector_t::const_iterator ppMark = vMarksToCopy.begin();
159 40 : ppMark != vMarksToCopy.end();
160 : ++ppMark)
161 : {
162 3 : const ::sw::mark::IMark* const pMark = *ppMark;
163 3 : SwPaM aTmpPam(*pCpyStt);
164 3 : lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetMarkPos().nNode.GetIndex(), nDelCount);
165 3 : lcl_SetCpyPos( pMark->GetMarkPos(), rStt, *pCpyStt, *aTmpPam.GetPoint(), nDelCount);
166 3 : if(pMark->IsExpanded())
167 : {
168 0 : aTmpPam.SetMark();
169 0 : lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetOtherMarkPos().nNode.GetIndex(), nDelCount);
170 0 : lcl_SetCpyPos(pMark->GetOtherMarkPos(), rStt, *pCpyStt, *aTmpPam.GetMark(), nDelCount);
171 : }
172 :
173 3 : ::sw::mark::IMark* const pNewMark = pDestDoc->getIDocumentMarkAccess()->makeMark(
174 : aTmpPam,
175 3 : pMark->GetName(),
176 6 : IDocumentMarkAccess::GetType(*pMark));
177 : // Explicitly try to get exactly the same name as in the source
178 : // because NavigatorReminders, DdeBookmarks etc. ignore the proposed name
179 3 : pDestDoc->getIDocumentMarkAccess()->renameMark(pNewMark, pMark->GetName());
180 :
181 : // copying additional attributes for bookmarks or fieldmarks
182 : ::sw::mark::IBookmark* const pNewBookmark =
183 3 : dynamic_cast< ::sw::mark::IBookmark* const >(pNewMark);
184 3 : if(pNewBookmark)
185 : {
186 0 : const ::sw::mark::IBookmark* const pOldBookmark = dynamic_cast< const ::sw::mark::IBookmark* >(pMark);
187 0 : pNewBookmark->SetKeyCode(pOldBookmark->GetKeyCode());
188 0 : pNewBookmark->SetShortName(pOldBookmark->GetShortName());
189 : }
190 : ::sw::mark::IFieldmark* const pNewFieldmark =
191 3 : dynamic_cast< ::sw::mark::IFieldmark* const >(pNewMark);
192 3 : if(pNewFieldmark)
193 : {
194 0 : const ::sw::mark::IFieldmark* const pOldFieldmark = dynamic_cast< const ::sw::mark::IFieldmark* >(pMark);
195 0 : pNewFieldmark->SetFieldname(pOldFieldmark->GetFieldname());
196 0 : pNewFieldmark->SetFieldHelptext(pOldFieldmark->GetFieldHelptext());
197 0 : ::sw::mark::IFieldmark::parameter_map_t* pNewParams = pNewFieldmark->GetParameters();
198 0 : const ::sw::mark::IFieldmark::parameter_map_t* pOldParams = pOldFieldmark->GetParameters();
199 0 : ::sw::mark::IFieldmark::parameter_map_t::const_iterator pIt = pOldParams->begin();
200 0 : for (; pIt != pOldParams->end(); ++pIt )
201 : {
202 0 : pNewParams->insert( *pIt );
203 : }
204 : }
205 :
206 : ::sfx2::Metadatable const*const pMetadatable(
207 3 : dynamic_cast< ::sfx2::Metadatable const* >(pMark));
208 : ::sfx2::Metadatable *const pNewMetadatable(
209 3 : dynamic_cast< ::sfx2::Metadatable * >(pNewMark));
210 3 : if (pMetadatable && pNewMetadatable)
211 : {
212 0 : pNewMetadatable->RegisterAsCopyOf(*pMetadatable);
213 : }
214 20 : }
215 17 : }
216 : }
217 :
218 : // Structure for the mapping from old and new frame formats to the
219 : // boxes and lines of a table
220 : struct _MapTblFrmFmt
221 : {
222 : const SwFrmFmt *pOld, *pNew;
223 6 : _MapTblFrmFmt( const SwFrmFmt *pOldFmt, const SwFrmFmt*pNewFmt )
224 6 : : pOld( pOldFmt ), pNew( pNewFmt )
225 6 : {}
226 : };
227 :
228 : typedef std::vector<_MapTblFrmFmt> _MapTblFrmFmts;
229 :
230 213 : SwCntntNode* SwTxtNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
231 : {
232 : // the Copy-Textnode is the Node with the Text, the Copy-Attrnode is the
233 : // node with the collection and hard attributes. Normally ist the same
234 : // node, but if insert a glossary without formatting, then the Attrnode
235 : // is the prev node of the destionation position in dest. document.
236 213 : SwTxtNode* pCpyTxtNd = (SwTxtNode*)this;
237 213 : SwTxtNode* pCpyAttrNd = pCpyTxtNd;
238 :
239 : // Copy the formats to the other document
240 213 : SwTxtFmtColl* pColl = 0;
241 213 : if( pDoc->IsInsOnlyTextGlossary() )
242 : {
243 0 : SwNodeIndex aIdx( rIdx, -1 );
244 0 : if( aIdx.GetNode().IsTxtNode() )
245 : {
246 0 : pCpyAttrNd = aIdx.GetNode().GetTxtNode();
247 0 : pColl = &pCpyAttrNd->GetTxtColl()->GetNextTxtFmtColl();
248 0 : }
249 : }
250 213 : if( !pColl )
251 213 : pColl = pDoc->CopyTxtColl( *GetTxtColl() );
252 :
253 213 : SwTxtNode* pTxtNd = pDoc->GetNodes().MakeTxtNode( rIdx, pColl );
254 :
255 : // METADATA: register copy
256 213 : pTxtNd->RegisterAsCopyOf(*pCpyTxtNd);
257 :
258 : // Copy Attribute/Text
259 213 : if( !pCpyAttrNd->HasSwAttrSet() )
260 : // An AttrSet was added for numbering, so delete it
261 189 : pTxtNd->ResetAllAttr();
262 :
263 : // if Copy-Textnode unequal to Copy-Attrnode, then copy first
264 : // the attributes into the new Node.
265 213 : if( pCpyAttrNd != pCpyTxtNd )
266 : {
267 0 : pCpyAttrNd->CopyAttr( pTxtNd, 0, 0 );
268 0 : if( pCpyAttrNd->HasSwAttrSet() )
269 : {
270 0 : SwAttrSet aSet( *pCpyAttrNd->GetpSwAttrSet() );
271 0 : aSet.ClearItem( RES_PAGEDESC );
272 0 : aSet.ClearItem( RES_BREAK );
273 0 : aSet.CopyToModify( *pTxtNd );
274 : }
275 : }
276 :
277 : // Is that enough? What about PostIts/Fields/FieldTypes?
278 : // #i96213# - force copy of all attributes
279 213 : pCpyTxtNd->CopyText( pTxtNd, SwIndex( pCpyTxtNd ),
280 426 : pCpyTxtNd->GetTxt().Len(), true );
281 :
282 213 : if( RES_CONDTXTFMTCOLL == pColl->Which() )
283 0 : pTxtNd->ChkCondColl();
284 :
285 213 : return pTxtNd;
286 : }
287 :
288 6 : static bool lcl_SrchNew( const _MapTblFrmFmt& rMap, const SwFrmFmt** pPara )
289 : {
290 6 : if( rMap.pOld != *pPara )
291 6 : return true;
292 0 : *pPara = rMap.pNew;
293 0 : return false;
294 : }
295 :
296 : struct _CopyTable
297 : {
298 : SwDoc* pDoc;
299 : sal_uLong nOldTblSttIdx;
300 : _MapTblFrmFmts& rMapArr;
301 : SwTableLine* pInsLine;
302 : SwTableBox* pInsBox;
303 : SwTableNode *pTblNd;
304 : const SwTable *pOldTable;
305 :
306 2 : _CopyTable( SwDoc* pDc, _MapTblFrmFmts& rArr, sal_uLong nOldStt,
307 : SwTableNode& rTblNd, const SwTable* pOldTbl )
308 : : pDoc(pDc), nOldTblSttIdx(nOldStt), rMapArr(rArr),
309 2 : pInsLine(0), pInsBox(0), pTblNd(&rTblNd), pOldTable( pOldTbl )
310 2 : {}
311 : };
312 :
313 : static void lcl_CopyTblLine( const SwTableLine* pLine, _CopyTable* pCT );
314 :
315 4 : static void lcl_CopyTblBox( SwTableBox* pBox, _CopyTable* pCT )
316 : {
317 4 : SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)pBox->GetFrmFmt();
318 10 : for( _MapTblFrmFmts::const_iterator it = pCT->rMapArr.begin(); it != pCT->rMapArr.end(); ++it )
319 6 : if ( !lcl_SrchNew( *it, (const SwFrmFmt**)&pBoxFmt ) )
320 0 : break;
321 4 : if( pBoxFmt == pBox->GetFrmFmt() ) // Create a new one?
322 : {
323 : const SfxPoolItem* pItem;
324 4 : if( SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_FORMULA, sal_False,
325 4 : &pItem ) && ((SwTblBoxFormula*)pItem)->IsIntrnlName() )
326 : {
327 0 : ((SwTblBoxFormula*)pItem)->PtrToBoxNm( pCT->pOldTable );
328 : }
329 :
330 4 : pBoxFmt = pCT->pDoc->MakeTableBoxFmt();
331 4 : pBoxFmt->CopyAttrs( *pBox->GetFrmFmt() );
332 :
333 4 : if( pBox->GetSttIdx() )
334 : {
335 4 : SvNumberFormatter* pN = pCT->pDoc->GetNumberFormatter( sal_False );
336 4 : if( pN && pN->HasMergeFmtTbl() && SFX_ITEM_SET == pBoxFmt->
337 0 : GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem ) )
338 : {
339 0 : sal_uLong nOldIdx = ((SwTblBoxNumFormat*)pItem)->GetValue();
340 0 : sal_uLong nNewIdx = pN->GetMergeFmtIndex( nOldIdx );
341 0 : if( nNewIdx != nOldIdx )
342 0 : pBoxFmt->SetFmtAttr( SwTblBoxNumFormat( nNewIdx ));
343 :
344 : }
345 : }
346 :
347 4 : pCT->rMapArr.push_back( _MapTblFrmFmt( pBox->GetFrmFmt(), pBoxFmt ) );
348 : }
349 :
350 4 : sal_uInt16 nLines = pBox->GetTabLines().size();
351 : SwTableBox* pNewBox;
352 4 : if( nLines )
353 0 : pNewBox = new SwTableBox( pBoxFmt, nLines, pCT->pInsLine );
354 : else
355 : {
356 : SwNodeIndex aNewIdx( *pCT->pTblNd,
357 4 : pBox->GetSttIdx() - pCT->nOldTblSttIdx );
358 : OSL_ENSURE( aNewIdx.GetNode().IsStartNode(), "Index is not on the start node" );
359 4 : pNewBox = new SwTableBox( pBoxFmt, aNewIdx, pCT->pInsLine );
360 4 : pNewBox->setRowSpan( pBox->getRowSpan() );
361 : }
362 :
363 4 : pCT->pInsLine->GetTabBoxes().push_back( pNewBox );
364 :
365 4 : if( nLines )
366 : {
367 0 : _CopyTable aPara( *pCT );
368 0 : aPara.pInsBox = pNewBox;
369 0 : BOOST_FOREACH( const SwTableLine* pLine, pBox->GetTabLines() )
370 0 : lcl_CopyTblLine( pLine, &aPara );
371 : }
372 4 : else if( pNewBox->IsInHeadline( &pCT->pTblNd->GetTable() ))
373 : // In the headline, the paragraphs must match conditional styles
374 4 : pNewBox->GetSttNd()->CheckSectionCondColl();
375 4 : }
376 :
377 2 : static void lcl_CopyTblLine( const SwTableLine* pLine, _CopyTable* pCT )
378 : {
379 2 : SwTableLineFmt* pLineFmt = (SwTableLineFmt*)pLine->GetFrmFmt();
380 2 : for( _MapTblFrmFmts::const_iterator it = pCT->rMapArr.begin(); it != pCT->rMapArr.end(); ++it )
381 0 : if ( !lcl_SrchNew( *it, (const SwFrmFmt**)&pLineFmt ) )
382 0 : break;
383 2 : if( pLineFmt == pLine->GetFrmFmt() ) // Create a new one?
384 : {
385 2 : pLineFmt = pCT->pDoc->MakeTableLineFmt();
386 2 : pLineFmt->CopyAttrs( *pLine->GetFrmFmt() );
387 2 : pCT->rMapArr.push_back( _MapTblFrmFmt( pLine->GetFrmFmt(), pLineFmt ) );
388 : }
389 : SwTableLine* pNewLine = new SwTableLine( pLineFmt,
390 2 : pLine->GetTabBoxes().size(), pCT->pInsBox );
391 : // Insert the new row into the table
392 2 : if( pCT->pInsBox )
393 : {
394 0 : pCT->pInsBox->GetTabLines().push_back( pNewLine );
395 : }
396 : else
397 : {
398 2 : pCT->pTblNd->GetTable().GetTabLines().push_back( pNewLine );
399 : }
400 2 : pCT->pInsLine = pNewLine;
401 18 : for( SwTableBoxes::iterator it = ((SwTableLine*)pLine)->GetTabBoxes().begin();
402 12 : it != ((SwTableLine*)pLine)->GetTabBoxes().end(); ++it)
403 4 : lcl_CopyTblBox(*it, pCT );
404 2 : }
405 :
406 2 : SwTableNode* SwTableNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
407 : {
408 : // In which array are we? Nodes? UndoNodes?
409 2 : SwNodes& rNds = (SwNodes&)GetNodes();
410 :
411 : {
412 2 : if( rIdx < pDoc->GetNodes().GetEndOfInserts().GetIndex() &&
413 0 : rIdx >= pDoc->GetNodes().GetEndOfInserts().StartOfSectionIndex() )
414 0 : return 0;
415 : }
416 :
417 : // Copy the TableFrmFmt
418 2 : String sTblName( GetTable().GetFrmFmt()->GetName() );
419 2 : if( !pDoc->IsCopyIsMove() )
420 : {
421 1 : const SwFrmFmts& rTblFmts = *pDoc->GetTblFrmFmts();
422 3 : for( sal_uInt16 n = rTblFmts.size(); n; )
423 2 : if( rTblFmts[ --n ]->GetName() == sTblName )
424 : {
425 1 : sTblName = pDoc->GetUniqueTblName();
426 1 : break;
427 : }
428 : }
429 :
430 2 : SwFrmFmt* pTblFmt = pDoc->MakeTblFrmFmt( sTblName, pDoc->GetDfltFrmFmt() );
431 2 : pTblFmt->CopyAttrs( *GetTable().GetFrmFmt() );
432 2 : SwTableNode* pTblNd = new SwTableNode( rIdx );
433 2 : SwEndNode* pEndNd = new SwEndNode( rIdx, *pTblNd );
434 2 : SwNodeIndex aInsPos( *pEndNd );
435 :
436 2 : SwTable& rTbl = (SwTable&)pTblNd->GetTable();
437 2 : rTbl.RegisterToFormat( *pTblFmt );
438 :
439 2 : rTbl.SetRowsToRepeat( GetTable().GetRowsToRepeat() );
440 2 : rTbl.SetTblChgMode( GetTable().GetTblChgMode() );
441 2 : rTbl.SetTableModel( GetTable().IsNewModel() );
442 :
443 2 : SwDDEFieldType* pDDEType = 0;
444 2 : if( IS_TYPE( SwDDETable, &GetTable() ))
445 : {
446 : // We're copying a DDE table
447 : // Is the field type available in the new document?
448 0 : pDDEType = ((SwDDETable&)GetTable()).GetDDEFldType();
449 0 : if( pDDEType->IsDeleted() )
450 0 : pDoc->InsDeletedFldType( *pDDEType );
451 : else
452 0 : pDDEType = (SwDDEFieldType*)pDoc->InsertFldType( *pDDEType );
453 : OSL_ENSURE( pDDEType, "unknown FieldType" );
454 :
455 : // Swap the table pointers in the node
456 0 : SwDDETable* pNewTable = new SwDDETable( pTblNd->GetTable(), pDDEType );
457 0 : pTblNd->SetNewTable( pNewTable, sal_False );
458 : }
459 : // First copy the content of the tables, we will later assign the
460 : // boxes/lines and create the frames
461 2 : SwNodeRange aRg( *this, +1, *EndOfSectionNode() );
462 :
463 : // If there is a table in this table, the table format for the outer table
464 : // does not seem to be used, because the table does not have any contents yet
465 : // (see IsUsed). Therefore the inner table gets the same name as the outer table.
466 : // We have to make sure that the table node of the SwTable is accessible, even
467 : // without any content in m_TabSortContentBoxes. #i26629#
468 2 : pTblNd->GetTable().SetTableNode( pTblNd );
469 2 : rNds._Copy( aRg, aInsPos, sal_False );
470 2 : pTblNd->GetTable().SetTableNode( 0 );
471 :
472 : // Special case for a single box
473 2 : if( 1 == GetTable().GetTabSortBoxes().size() )
474 : {
475 0 : aRg.aStart.Assign( *pTblNd, 1 );
476 0 : aRg.aEnd.Assign( *pTblNd->EndOfSectionNode() );
477 0 : pDoc->GetNodes().SectionDown( &aRg, SwTableBoxStartNode );
478 : }
479 :
480 : // Delete all frames from the copied area, they will be created
481 : // during the generation of the table frame
482 2 : pTblNd->DelFrms();
483 :
484 2 : _MapTblFrmFmts aMapArr;
485 2 : _CopyTable aPara( pDoc, aMapArr, GetIndex(), *pTblNd, &GetTable() );
486 :
487 4 : BOOST_FOREACH(const SwTableLine* pLine, GetTable().GetTabLines() )
488 2 : lcl_CopyTblLine( pLine, &aPara );
489 :
490 2 : if( pDDEType )
491 0 : pDDEType->IncRefCnt();
492 :
493 : CHECK_TABLE( GetTable() );
494 2 : return pTblNd;
495 : }
496 :
497 16 : void SwTxtNode::CopyCollFmt( SwTxtNode& rDestNd )
498 : {
499 : // Copy the formats into the other document:
500 : // Special case for PageBreak/PageDesc/ColBrk
501 16 : SwDoc* pDestDoc = rDestNd.GetDoc();
502 16 : SwAttrSet aPgBrkSet( pDestDoc->GetAttrPool(), aBreakSetRange );
503 : const SwAttrSet* pSet;
504 :
505 16 : if( 0 != ( pSet = rDestNd.GetpSwAttrSet() ) )
506 : {
507 : // Special cases for Break-Attributes
508 : const SfxPoolItem* pAttr;
509 13 : if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, sal_False, &pAttr ) )
510 0 : aPgBrkSet.Put( *pAttr );
511 :
512 13 : if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC, sal_False, &pAttr ) )
513 0 : aPgBrkSet.Put( *pAttr );
514 : }
515 :
516 16 : rDestNd.ChgFmtColl( pDestDoc->CopyTxtColl( *GetTxtColl() ));
517 16 : if( 0 != ( pSet = GetpSwAttrSet() ) )
518 13 : pSet->CopyToModify( rDestNd );
519 :
520 16 : if( aPgBrkSet.Count() )
521 0 : rDestNd.SetAttr( aPgBrkSet );
522 16 : }
523 :
524 :
525 : // Copy method from SwDoc
526 : // Prevent copying in Flys that are anchored in the area
527 17 : static sal_Bool lcl_ChkFlyFly( SwDoc* pDoc, sal_uLong nSttNd, sal_uLong nEndNd,
528 : sal_uLong nInsNd )
529 : {
530 17 : const SwFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts();
531 :
532 53 : for( sal_uInt16 n = 0; n < rFrmFmtTbl.size(); ++n )
533 : {
534 36 : SwFrmFmt const*const pFmt = rFrmFmtTbl[n];
535 36 : SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
536 36 : SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
537 139 : if (pAPos &&
538 20 : ((FLY_AS_CHAR == pAnchor->GetAnchorId()) ||
539 20 : (FLY_AT_CHAR == pAnchor->GetAnchorId()) ||
540 16 : (FLY_AT_FLY == pAnchor->GetAnchorId()) ||
541 16 : (FLY_AT_PARA == pAnchor->GetAnchorId())) &&
542 20 : nSttNd <= pAPos->nNode.GetIndex() &&
543 11 : pAPos->nNode.GetIndex() < nEndNd )
544 : {
545 6 : const SwFmtCntnt& rCntnt = pFmt->GetCntnt();
546 : SwStartNode* pSNd;
547 8 : if( !rCntnt.GetCntntIdx() ||
548 2 : 0 == ( pSNd = rCntnt.GetCntntIdx()->GetNode().GetStartNode() ))
549 4 : continue;
550 :
551 4 : if( pSNd->GetIndex() < nInsNd &&
552 2 : nInsNd < pSNd->EndOfSectionIndex() )
553 : // Do not copy !
554 0 : return sal_True;
555 :
556 2 : if( lcl_ChkFlyFly( pDoc, pSNd->GetIndex(),
557 2 : pSNd->EndOfSectionIndex(), nInsNd ) )
558 : // Do not copy !
559 0 : return sal_True;
560 : }
561 : }
562 :
563 17 : return sal_False;
564 : }
565 :
566 0 : static void lcl_DeleteRedlines( const SwPaM& rPam, SwPaM& rCpyPam )
567 : {
568 0 : const SwDoc* pSrcDoc = rPam.GetDoc();
569 0 : const SwRedlineTbl& rTbl = pSrcDoc->GetRedlineTbl();
570 0 : if( !rTbl.empty() )
571 : {
572 0 : SwDoc* pDestDoc = rCpyPam.GetDoc();
573 0 : SwPosition* pCpyStt = rCpyPam.Start(), *pCpyEnd = rCpyPam.End();
574 0 : SwPaM* pDelPam = 0;
575 0 : const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
576 : // We have to count the "non-copied" nodes
577 0 : sal_uLong nDelCount = 0;
578 0 : SwNodeIndex aCorrIdx( pStt->nNode );
579 :
580 0 : sal_uInt16 n = 0;
581 0 : pSrcDoc->GetRedline( *pStt, &n );
582 0 : for( ; n < rTbl.size(); ++n )
583 : {
584 0 : const SwRedline* pRedl = rTbl[ n ];
585 0 : if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetType() && pRedl->IsVisible() )
586 : {
587 0 : const SwPosition *pRStt = pRedl->Start(), *pREnd = pRedl->End();
588 :
589 0 : SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd );
590 0 : switch( eCmpPos )
591 : {
592 : case POS_COLLIDE_END:
593 : case POS_BEFORE:
594 : // Pos1 is before Pos2
595 0 : break;
596 :
597 : case POS_COLLIDE_START:
598 : case POS_BEHIND:
599 : // Pos1 is after Pos2
600 0 : n = rTbl.size();
601 0 : break;
602 :
603 : default:
604 : {
605 0 : pDelPam = new SwPaM( *pCpyStt, pDelPam );
606 0 : if( *pStt < *pRStt )
607 : {
608 0 : lcl_NonCopyCount( rPam, aCorrIdx, pRStt->nNode.GetIndex(), nDelCount );
609 : lcl_SetCpyPos( *pRStt, *pStt, *pCpyStt,
610 0 : *pDelPam->GetPoint(), nDelCount );
611 : }
612 0 : pDelPam->SetMark();
613 :
614 0 : if( *pEnd < *pREnd )
615 0 : *pDelPam->GetPoint() = *pCpyEnd;
616 : else
617 : {
618 0 : lcl_NonCopyCount( rPam, aCorrIdx, pREnd->nNode.GetIndex(), nDelCount );
619 : lcl_SetCpyPos( *pREnd, *pStt, *pCpyStt,
620 0 : *pDelPam->GetPoint(), nDelCount );
621 : }
622 : }
623 : }
624 : }
625 : }
626 :
627 0 : if( pDelPam )
628 : {
629 0 : RedlineMode_t eOld = pDestDoc->GetRedlineMode();
630 0 : pDestDoc->SetRedlineMode_intern( (RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
631 :
632 0 : ::sw::UndoGuard const undoGuard(pDestDoc->GetIDocumentUndoRedo());
633 :
634 0 : do {
635 0 : pDestDoc->DeleteAndJoin( *(SwPaM*)pDelPam->GetNext() );
636 0 : if( pDelPam->GetNext() == pDelPam )
637 0 : break;
638 0 : delete pDelPam->GetNext();
639 : } while( sal_True );
640 0 : delete pDelPam;
641 :
642 0 : pDestDoc->SetRedlineMode_intern( eOld );
643 0 : }
644 : }
645 0 : }
646 :
647 0 : static void lcl_DeleteRedlines( const SwNodeRange& rRg, SwNodeRange& rCpyRg )
648 : {
649 0 : SwDoc* pSrcDoc = rRg.aStart.GetNode().GetDoc();
650 0 : if( !pSrcDoc->GetRedlineTbl().empty() )
651 : {
652 0 : SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
653 0 : SwPaM aCpyTmp( rCpyRg.aStart, rCpyRg.aEnd );
654 0 : lcl_DeleteRedlines( aRgTmp, aCpyTmp );
655 : }
656 0 : }
657 :
658 : // Copy an area into this document or into another document
659 : bool
660 19 : SwDoc::CopyRange( SwPaM& rPam, SwPosition& rPos, const bool bCopyAll ) const
661 : {
662 19 : const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
663 :
664 19 : SwDoc* pDoc = rPos.nNode.GetNode().GetDoc();
665 19 : bool bColumnSel = pDoc->IsClipBoard() && pDoc->IsColumnSelection();
666 :
667 : // Catch if there's no copy to do
668 19 : if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) )
669 3 : return false;
670 :
671 : // Prevent copying in Flys that are anchored in the area
672 16 : if( pDoc == this )
673 : {
674 : // Correct the Start-/EndNode
675 16 : sal_uLong nStt = pStt->nNode.GetIndex(),
676 16 : nEnd = pEnd->nNode.GetIndex(),
677 16 : nDiff = nEnd - nStt +1;
678 16 : SwNode* pNd = GetNodes()[ nStt ];
679 16 : if( pNd->IsCntntNode() && pStt->nContent.GetIndex() )
680 1 : ++nStt, --nDiff;
681 32 : if( (pNd = GetNodes()[ nEnd ])->IsCntntNode() &&
682 16 : ((SwCntntNode*)pNd)->Len() != pEnd->nContent.GetIndex() )
683 0 : --nEnd, --nDiff;
684 31 : if( nDiff &&
685 15 : lcl_ChkFlyFly( pDoc, nStt, nEnd, rPos.nNode.GetIndex() ) )
686 : {
687 0 : return false;
688 : }
689 : }
690 :
691 16 : SwPaM* pRedlineRange = 0;
692 47 : if( pDoc->IsRedlineOn() ||
693 31 : (!pDoc->IsIgnoreRedline() && !pDoc->GetRedlineTbl().empty() ) )
694 0 : pRedlineRange = new SwPaM( rPos );
695 :
696 16 : RedlineMode_t eOld = pDoc->GetRedlineMode();
697 :
698 16 : bool bRet = false;
699 :
700 16 : if( pDoc != this )
701 : { // ordinary copy
702 0 : bRet = CopyImpl( rPam, rPos, true, bCopyAll, pRedlineRange );
703 : }
704 32 : else if( ! ( *pStt <= rPos && rPos < *pEnd &&
705 0 : ( pStt->nNode != pEnd->nNode ||
706 16 : !pStt->nNode.GetNode().IsTxtNode() )) )
707 : {
708 : // Copy to a position outside of the area, or copy a single TextNode
709 : // Do an ordinary copy
710 16 : bRet = CopyImpl( rPam, rPos, true, bCopyAll, pRedlineRange );
711 : }
712 : else
713 : {
714 : // Copy the area in itself
715 : // Special case for handling an area with several nodes,
716 : // or a single node that is not a TextNode
717 : OSL_ENSURE( this == pDoc, " invalid copy branch!" );
718 : OSL_FAIL("mst: i thought this could be dead code;"
719 : "please tell me what you did to get here!");
720 0 : pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
721 :
722 : // Then copy the area to the underlying document area
723 : // (with start/end nodes clamped) and move them to
724 : // the desired position.
725 :
726 0 : SwUndoCpyDoc* pUndo = 0;
727 : // Save the Undo area
728 0 : SwPaM aPam( rPos );
729 0 : if (pDoc->GetIDocumentUndoRedo().DoesUndo())
730 : {
731 0 : pDoc->GetIDocumentUndoRedo().ClearRedo();
732 0 : pUndo = new SwUndoCpyDoc( aPam );
733 : }
734 :
735 : {
736 0 : ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo());
737 0 : SwStartNode* pSttNd = pDoc->GetNodes().MakeEmptySection(
738 0 : SwNodeIndex( GetNodes().GetEndOfAutotext() ));
739 0 : aPam.GetPoint()->nNode = *pSttNd->EndOfSectionNode();
740 : // copy without Frames
741 0 : pDoc->CopyImpl( rPam, *aPam.GetPoint(), false, bCopyAll, 0 );
742 :
743 0 : aPam.GetPoint()->nNode = pDoc->GetNodes().GetEndOfAutotext();
744 0 : aPam.SetMark();
745 : SwCntntNode* pNode =
746 0 : pDoc->GetNodes().GoPrevious( &aPam.GetMark()->nNode );
747 0 : pNode->MakeEndIndex( &aPam.GetMark()->nContent );
748 :
749 0 : aPam.GetPoint()->nNode = *aPam.GetNode()->StartOfSectionNode();
750 0 : pNode = pDoc->GetNodes().GoNext( &aPam.GetPoint()->nNode );
751 0 : pNode->MakeStartIndex( &aPam.GetPoint()->nContent );
752 : // move to desired position
753 0 : pDoc->MoveRange( aPam, rPos, DOC_MOVEDEFAULT );
754 :
755 0 : pNode = aPam.GetCntntNode();
756 0 : *aPam.GetPoint() = rPos; // Move the cursor for Undo
757 0 : aPam.SetMark(); // also move the Mark
758 0 : aPam.DeleteMark(); // But don't mark any area
759 0 : pDoc->DeleteSection( pNode ); // Delete the area again
760 : }
761 :
762 : // if Undo is enabled, store the insertion range
763 0 : if (pDoc->GetIDocumentUndoRedo().DoesUndo())
764 : {
765 0 : pUndo->SetInsertRange( aPam );
766 0 : pDoc->GetIDocumentUndoRedo().AppendUndo(pUndo);
767 : }
768 :
769 0 : if( pRedlineRange )
770 : {
771 0 : pRedlineRange->SetMark();
772 0 : *pRedlineRange->GetPoint() = *aPam.GetPoint();
773 0 : *pRedlineRange->GetMark() = *aPam.GetMark();
774 : }
775 :
776 0 : pDoc->SetModified();
777 0 : bRet = true;
778 : }
779 :
780 16 : pDoc->SetRedlineMode_intern( eOld );
781 16 : if( pRedlineRange )
782 : {
783 0 : if( pDoc->IsRedlineOn() )
784 0 : pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, *pRedlineRange ), true);
785 : else
786 0 : pDoc->SplitRedline( *pRedlineRange );
787 0 : delete pRedlineRange;
788 : }
789 :
790 16 : return bRet;
791 : }
792 :
793 2 : static bool lcl_MarksWholeNode(const SwPaM & rPam)
794 : {
795 2 : bool bResult = false;
796 2 : const SwPosition* pStt = rPam.Start();
797 2 : const SwPosition* pEnd = rPam.End();
798 :
799 2 : if (NULL != pStt && NULL != pEnd)
800 : {
801 2 : const SwTxtNode* pSttNd = pStt->nNode.GetNode().GetTxtNode();
802 2 : const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode();
803 :
804 5 : if (NULL != pSttNd && NULL != pEndNd &&
805 2 : pStt->nContent.GetIndex() == 0 &&
806 1 : pEnd->nContent.GetIndex() == pEndNd->Len())
807 : {
808 1 : bResult = true;
809 : }
810 : }
811 :
812 2 : return bResult;
813 : }
814 :
815 : // #i86492#
816 0 : static bool lcl_ContainsOnlyParagraphsInList( const SwPaM& rPam )
817 : {
818 0 : bool bRet = false;
819 :
820 0 : const SwTxtNode* pTxtNd = rPam.Start()->nNode.GetNode().GetTxtNode();
821 0 : const SwTxtNode* pEndTxtNd = rPam.End()->nNode.GetNode().GetTxtNode();
822 0 : if ( pTxtNd && pTxtNd->IsInList() &&
823 0 : pEndTxtNd && pEndTxtNd->IsInList() )
824 : {
825 0 : bRet = true;
826 0 : SwNodeIndex aIdx(rPam.Start()->nNode);
827 :
828 0 : do
829 : {
830 0 : ++aIdx;
831 0 : pTxtNd = aIdx.GetNode().GetTxtNode();
832 :
833 0 : if ( !pTxtNd || !pTxtNd->IsInList() )
834 : {
835 0 : bRet = false;
836 0 : break;
837 : }
838 0 : } while ( pTxtNd && pTxtNd != pEndTxtNd );
839 : }
840 :
841 :
842 0 : return bRet;
843 : }
844 :
845 16 : bool SwDoc::CopyImpl( SwPaM& rPam, SwPosition& rPos,
846 : const bool bMakeNewFrms, const bool bCopyAll,
847 : SwPaM *const pCpyRange ) const
848 : {
849 16 : SwDoc* pDoc = rPos.nNode.GetNode().GetDoc();
850 16 : const bool bColumnSel = pDoc->IsClipBoard() && pDoc->IsColumnSelection();
851 :
852 16 : SwPosition* pStt = rPam.Start();
853 16 : SwPosition* pEnd = rPam.End();
854 :
855 : // Catch when there's no copy to do.
856 32 : if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) ||
857 : //JP 29.6.2001: 88963 - dont copy if inspos is in region of start to end
858 : //JP 15.11.2001: don't test inclusive the end, ever exclusive
859 16 : ( pDoc == this && *pStt <= rPos && rPos < *pEnd ))
860 : {
861 0 : return false;
862 : }
863 :
864 16 : const bool bEndEqualIns = pDoc == this && rPos == *pEnd;
865 :
866 : // If Undo is enabled, create the UndoCopy object
867 16 : SwUndoCpyDoc* pUndo = 0;
868 16 : SwPaM aCpyPam( rPos );
869 :
870 16 : SwTblNumFmtMerge aTNFM( *this, *pDoc );
871 :
872 16 : if (pDoc->GetIDocumentUndoRedo().DoesUndo())
873 : {
874 0 : pUndo = new SwUndoCpyDoc( aCpyPam );
875 0 : pDoc->GetIDocumentUndoRedo().AppendUndo( pUndo );
876 : }
877 :
878 16 : RedlineMode_t eOld = pDoc->GetRedlineMode();
879 16 : pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
880 :
881 : // Move the PaM one node back from the insert position, so that
882 : // the position doesn't get moved
883 16 : aCpyPam.SetMark();
884 16 : sal_Bool bCanMoveBack = aCpyPam.Move( fnMoveBackward, fnGoCntnt );
885 : // If the position was shifted from more than one node, an end node has been skipped
886 16 : bool bAfterTable = false;
887 16 : if ( ( rPos.nNode.GetIndex() - aCpyPam.GetPoint()->nNode.GetIndex() ) > 1 )
888 : {
889 : // First go back to the original place
890 0 : aCpyPam.GetPoint()->nNode = rPos.nNode;
891 0 : aCpyPam.GetPoint()->nContent = rPos.nContent;
892 :
893 0 : bCanMoveBack = false;
894 0 : bAfterTable = true;
895 : }
896 16 : if( !bCanMoveBack )
897 16 : aCpyPam.GetPoint()->nNode--;
898 :
899 16 : SwNodeRange aRg( pStt->nNode, pEnd->nNode );
900 16 : SwNodeIndex aInsPos( rPos.nNode );
901 16 : const bool bOneNode = pStt->nNode == pEnd->nNode;
902 16 : SwTxtNode* pSttTxtNd = pStt->nNode.GetNode().GetTxtNode();
903 16 : SwTxtNode* pEndTxtNd = pEnd->nNode.GetNode().GetTxtNode();
904 16 : SwTxtNode* pDestTxtNd = aInsPos.GetNode().GetTxtNode();
905 16 : bool bCopyCollFmt = !pDoc->IsInsOnlyTextGlossary() &&
906 16 : ( ( pDestTxtNd && !pDestTxtNd->GetTxt().Len() ) ||
907 32 : ( !bOneNode && !rPos.nContent.GetIndex() ) );
908 16 : bool bCopyBookmarks = true;
909 16 : sal_Bool bStartIsTxtNode = 0 != pSttTxtNd;
910 :
911 : // #i104585# copy outline num rule to clipboard (for ASCII filter)
912 16 : if (pDoc->IsClipBoard() && GetOutlineNumRule())
913 : {
914 0 : pDoc->SetOutlineNumRule(*GetOutlineNumRule());
915 : }
916 :
917 : // #i86492#
918 : // Correct the search for a previous list:
919 : // First search for non-outline numbering list. Then search for non-outline
920 : // bullet list.
921 : // Keep also the <ListId> value for possible propagation.
922 16 : String aListIdToPropagate;
923 : const SwNumRule* pNumRuleToPropagate =
924 16 : pDoc->SearchNumRule( rPos, false, true, false, 0, aListIdToPropagate, true );
925 16 : if ( !pNumRuleToPropagate )
926 : {
927 : pNumRuleToPropagate =
928 16 : pDoc->SearchNumRule( rPos, false, false, false, 0, aListIdToPropagate, true );
929 : }
930 : // #i86492#
931 : // Do not propagate previous found list, if
932 : // - destination is an empty paragraph which is not in a list and
933 : // - source contains at least one paragraph which is not in a list
934 16 : if ( pNumRuleToPropagate &&
935 0 : pDestTxtNd && !pDestTxtNd->GetTxt().Len() && !pDestTxtNd->IsInList() &&
936 0 : !lcl_ContainsOnlyParagraphsInList( rPam ) )
937 : {
938 0 : pNumRuleToPropagate = 0;
939 : }
940 :
941 : // This do/while block is only there so that we can break out of it!
942 : do {
943 16 : if( pSttTxtNd )
944 : {
945 : // Don't copy the beginning completely?
946 16 : if( !bCopyCollFmt || bColumnSel || pStt->nContent.GetIndex() )
947 : {
948 1 : SwIndex aDestIdx( rPos.nContent );
949 1 : bool bCopyOk = false;
950 1 : if( !pDestTxtNd )
951 : {
952 0 : if( pStt->nContent.GetIndex() || bOneNode )
953 0 : pDestTxtNd = pDoc->GetNodes().MakeTxtNode( aInsPos,
954 0 : pDoc->GetTxtCollFromPool(RES_POOLCOLL_STANDARD));
955 : else
956 : {
957 0 : pDestTxtNd = static_cast<SwTxtNode*>(pSttTxtNd->MakeCopy( pDoc, aInsPos ));
958 0 : bCopyOk = true;
959 : }
960 0 : aDestIdx.Assign( pDestTxtNd, 0 );
961 0 : bCopyCollFmt = true;
962 : }
963 1 : else if( !bOneNode || bColumnSel )
964 : {
965 0 : xub_StrLen nCntntEnd = pEnd->nContent.GetIndex();
966 : {
967 0 : ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
968 0 : pDoc->SplitNode( rPos, false );
969 : }
970 :
971 0 : if( bCanMoveBack && rPos == *aCpyPam.GetPoint() )
972 : {
973 : // after the SplitNode, span the CpyPam correctly again
974 0 : aCpyPam.Move( fnMoveBackward, fnGoCntnt );
975 0 : aCpyPam.Move( fnMoveBackward, fnGoCntnt );
976 : }
977 :
978 0 : pDestTxtNd = pDoc->GetNodes()[ aInsPos.GetIndex()-1 ]->GetTxtNode();
979 0 : aDestIdx.Assign( pDestTxtNd, pDestTxtNd->GetTxt().Len() );
980 :
981 : // Correct the area again
982 0 : if( bEndEqualIns )
983 : {
984 0 : bool bChg = pEnd != rPam.GetPoint();
985 0 : if( bChg )
986 0 : rPam.Exchange();
987 0 : rPam.Move( fnMoveBackward, fnGoCntnt );
988 0 : if( bChg )
989 0 : rPam.Exchange();
990 :
991 0 : aRg.aEnd = pEnd->nNode;
992 0 : pEndTxtNd = pEnd->nNode.GetNode().GetTxtNode();
993 : }
994 0 : else if( rPos == *pEnd )
995 : {
996 : // The end was also moved
997 0 : pEnd->nNode--;
998 0 : pEnd->nContent.Assign( pDestTxtNd, nCntntEnd );
999 0 : aRg.aEnd = pEnd->nNode;
1000 0 : pEndTxtNd = pEnd->nNode.GetNode().GetTxtNode();
1001 : }
1002 : }
1003 :
1004 : // Safe numrule item at destination.
1005 : // #i86492# - Safe also <ListId> item of destination.
1006 1 : int aNumRuleState = SFX_ITEM_UNKNOWN;
1007 1 : SwNumRuleItem aNumRuleItem;
1008 1 : int aListIdState = SFX_ITEM_UNKNOWN;
1009 1 : SfxStringItem aListIdItem( RES_PARATR_LIST_ID, String() );
1010 : {
1011 1 : const SfxItemSet * pAttrSet = pDestTxtNd->GetpSwAttrSet();
1012 1 : if (pAttrSet != NULL)
1013 : {
1014 0 : const SfxPoolItem * pItem = NULL;
1015 0 : aNumRuleState = pAttrSet->GetItemState(RES_PARATR_NUMRULE, sal_False, &pItem);
1016 0 : if (SFX_ITEM_SET == aNumRuleState)
1017 0 : aNumRuleItem = *((SwNumRuleItem *) pItem);
1018 :
1019 : aListIdState =
1020 0 : pAttrSet->GetItemState(RES_PARATR_LIST_ID, sal_False, &pItem);
1021 0 : if (SFX_ITEM_SET == aListIdState)
1022 : {
1023 0 : aListIdItem.SetValue( static_cast<const SfxStringItem*>(pItem)->GetValue() );
1024 : }
1025 : }
1026 : }
1027 :
1028 1 : if( !bCopyOk )
1029 : {
1030 : const xub_StrLen nCpyLen = ( (bOneNode)
1031 1 : ? pEnd->nContent.GetIndex()
1032 0 : : pSttTxtNd->GetTxt().Len() )
1033 2 : - pStt->nContent.GetIndex();
1034 : pSttTxtNd->CopyText( pDestTxtNd, aDestIdx,
1035 1 : pStt->nContent, nCpyLen );
1036 1 : if( bEndEqualIns )
1037 0 : pEnd->nContent -= nCpyLen;
1038 : }
1039 :
1040 1 : if( bOneNode )
1041 : {
1042 1 : if( bCopyCollFmt )
1043 : {
1044 1 : pSttTxtNd->CopyCollFmt( *pDestTxtNd );
1045 :
1046 : /* If only a part of one paragraph is copied
1047 : restore the numrule at the destination. */
1048 : // #i86492# - restore also <ListId> item
1049 1 : if ( !lcl_MarksWholeNode(rPam) )
1050 : {
1051 1 : if (SFX_ITEM_SET == aNumRuleState)
1052 : {
1053 0 : pDestTxtNd->SetAttr(aNumRuleItem);
1054 : }
1055 : else
1056 : {
1057 1 : pDestTxtNd->ResetAttr(RES_PARATR_NUMRULE);
1058 : }
1059 1 : if (SFX_ITEM_SET == aListIdState)
1060 : {
1061 0 : pDestTxtNd->SetAttr(aListIdItem);
1062 : }
1063 : else
1064 : {
1065 1 : pDestTxtNd->ResetAttr(RES_PARATR_LIST_ID);
1066 : }
1067 : }
1068 : }
1069 :
1070 : break;
1071 : }
1072 :
1073 0 : aRg.aStart++;
1074 : }
1075 : }
1076 0 : else if( pDestTxtNd )
1077 : {
1078 : // Problems with insertion of table selections into "normal" text solved.
1079 : // We have to set the correct PaM for Undo, if this PaM starts in a textnode,
1080 : // the undo operation will try to merge this node after removing the table.
1081 : // If we didn't split a textnode, the PaM should start at the inserted table node
1082 0 : if( rPos.nContent.GetIndex() == pDestTxtNd->Len() )
1083 : { // Insertion at the last position of a textnode (empty or not)
1084 0 : ++aInsPos; // The table will be inserted behind the text node
1085 : }
1086 0 : else if( rPos.nContent.GetIndex() )
1087 : { // Insertion in the middle of a text node, it has to be split
1088 : // (and joined from undo)
1089 0 : bStartIsTxtNode = sal_True;
1090 :
1091 0 : xub_StrLen nCntntEnd = pEnd->nContent.GetIndex();
1092 : {
1093 0 : ::sw::UndoGuard const ug(pDoc->GetIDocumentUndoRedo());
1094 0 : pDoc->SplitNode( rPos, false );
1095 : }
1096 :
1097 0 : if( bCanMoveBack && rPos == *aCpyPam.GetPoint() )
1098 : {
1099 : // after the SplitNode, span the CpyPam correctly again
1100 0 : aCpyPam.Move( fnMoveBackward, fnGoCntnt );
1101 0 : aCpyPam.Move( fnMoveBackward, fnGoCntnt );
1102 : }
1103 :
1104 : // Correct the area again
1105 0 : if( bEndEqualIns )
1106 0 : aRg.aEnd--;
1107 : // The end would also be moved
1108 0 : else if( rPos == *pEnd )
1109 : {
1110 0 : rPos.nNode-=2;
1111 0 : rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(),
1112 0 : nCntntEnd );
1113 0 : rPos.nNode++;
1114 0 : aRg.aEnd--;
1115 : }
1116 : }
1117 0 : else if( bCanMoveBack )
1118 : { //Insertion at the first position of a text node. It will not be splitted, the table
1119 : // will be inserted before the text node.
1120 : // See below, before the SetInsertRange funciton of the undo object will be called,
1121 : // the CpyPam would be moved to the next content position. This has to be avoided
1122 : // We want to be moved to the table node itself thus we have to set bCanMoveBack
1123 : // and to manipulate aCpyPam.
1124 0 : bCanMoveBack = false;
1125 0 : aCpyPam.GetPoint()->nNode--;
1126 : }
1127 : }
1128 :
1129 15 : pDestTxtNd = aInsPos.GetNode().GetTxtNode();
1130 15 : if( pEndTxtNd )
1131 : {
1132 15 : SwIndex aDestIdx( rPos.nContent );
1133 15 : if( !pDestTxtNd )
1134 : {
1135 0 : pDestTxtNd = pDoc->GetNodes().MakeTxtNode( aInsPos,
1136 0 : pDoc->GetTxtCollFromPool(RES_POOLCOLL_STANDARD));
1137 0 : aDestIdx.Assign( pDestTxtNd, 0 );
1138 0 : aInsPos--;
1139 :
1140 : // if we have to insert an extra text node
1141 : // at the destination, this node will be our new destination
1142 : // (text) node, and thus we set bStartisTxtNode to true. This
1143 : // will ensure that this node will be deleted during Undo
1144 : // using JoinNext.
1145 : OSL_ENSURE( !bStartIsTxtNode, "Oops, undo may be instable now." );
1146 0 : bStartIsTxtNode = sal_True;
1147 : }
1148 :
1149 : // Save numrule at destination
1150 : // #i86492# - Safe also <ListId> item of destination.
1151 15 : int aNumRuleState = SFX_ITEM_UNKNOWN;
1152 15 : SwNumRuleItem aNumRuleItem;
1153 15 : int aListIdState = SFX_ITEM_UNKNOWN;
1154 15 : SfxStringItem aListIdItem( RES_PARATR_LIST_ID, String() );
1155 : {
1156 15 : const SfxItemSet* pAttrSet = pDestTxtNd->GetpSwAttrSet();
1157 15 : if (pAttrSet != NULL)
1158 : {
1159 0 : const SfxPoolItem * pItem = NULL;
1160 :
1161 : aNumRuleState =
1162 0 : pAttrSet->GetItemState(RES_PARATR_NUMRULE, sal_False, &pItem);
1163 0 : if (SFX_ITEM_SET == aNumRuleState)
1164 0 : aNumRuleItem = *((SwNumRuleItem *) pItem);
1165 :
1166 : aListIdState =
1167 0 : pAttrSet->GetItemState(RES_PARATR_LIST_ID, sal_False, &pItem);
1168 0 : if (SFX_ITEM_SET == aListIdState)
1169 0 : aListIdItem.SetValue( static_cast<const SfxStringItem*>(pItem)->GetValue() );
1170 : }
1171 : }
1172 :
1173 15 : const bool bEmptyDestNd = 0 == pDestTxtNd->GetTxt().Len();
1174 15 : pEndTxtNd->CopyText( pDestTxtNd, aDestIdx, SwIndex( pEndTxtNd ),
1175 30 : pEnd->nContent.GetIndex() );
1176 :
1177 : // Also copy all format templates
1178 15 : if( bCopyCollFmt && ( bOneNode || bEmptyDestNd ))
1179 : {
1180 15 : pEndTxtNd->CopyCollFmt( *pDestTxtNd );
1181 :
1182 15 : if ( bOneNode )
1183 : {
1184 : /* If only a part of one paragraph is copied
1185 : restore the numrule at the destination. */
1186 : // #i86492# - restore also <ListId> item
1187 1 : if ( !lcl_MarksWholeNode(rPam) )
1188 : {
1189 0 : if (SFX_ITEM_SET == aNumRuleState)
1190 : {
1191 0 : pDestTxtNd->SetAttr(aNumRuleItem);
1192 : }
1193 : else
1194 : {
1195 0 : pDestTxtNd->ResetAttr(RES_PARATR_NUMRULE);
1196 : }
1197 0 : if (SFX_ITEM_SET == aListIdState)
1198 : {
1199 0 : pDestTxtNd->SetAttr(aListIdItem);
1200 : }
1201 : else
1202 : {
1203 0 : pDestTxtNd->ResetAttr(RES_PARATR_LIST_ID);
1204 : }
1205 : }
1206 : }
1207 15 : }
1208 : }
1209 :
1210 15 : if( bCopyAll || aRg.aStart != aRg.aEnd )
1211 : {
1212 14 : SfxItemSet aBrkSet( pDoc->GetAttrPool(), aBreakSetRange );
1213 14 : if( pSttTxtNd && bCopyCollFmt && pDestTxtNd->HasSwAttrSet() )
1214 : {
1215 13 : aBrkSet.Put( *pDestTxtNd->GetpSwAttrSet() );
1216 13 : if( SFX_ITEM_SET == aBrkSet.GetItemState( RES_BREAK, sal_False ) )
1217 0 : pDestTxtNd->ResetAttr( RES_BREAK );
1218 13 : if( SFX_ITEM_SET == aBrkSet.GetItemState( RES_PAGEDESC, sal_False ) )
1219 0 : pDestTxtNd->ResetAttr( RES_PAGEDESC );
1220 : }
1221 :
1222 14 : if( aInsPos == pEnd->nNode )
1223 : {
1224 0 : SwNodeIndex aSaveIdx( aInsPos, -1 );
1225 0 : CopyWithFlyInFly( aRg, 0,aInsPos, bMakeNewFrms, sal_False );
1226 0 : ++aSaveIdx;
1227 0 : pEnd->nNode = aSaveIdx;
1228 0 : pEnd->nContent.Assign( aSaveIdx.GetNode().GetTxtNode(), 0 );
1229 : }
1230 : else
1231 14 : CopyWithFlyInFly( aRg, pEnd->nContent.GetIndex(), aInsPos, bMakeNewFrms, sal_False );
1232 :
1233 14 : bCopyBookmarks = false;
1234 :
1235 : // Put the breaks back into the first node
1236 14 : if( aBrkSet.Count() && 0 != ( pDestTxtNd = pDoc->GetNodes()[
1237 0 : aCpyPam.GetPoint()->nNode.GetIndex()+1 ]->GetTxtNode() ) )
1238 : {
1239 0 : pDestTxtNd->SetAttr( aBrkSet );
1240 14 : }
1241 : }
1242 : } while( sal_False );
1243 :
1244 : // Adjust position (in case it was moved / in another node)
1245 16 : rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(),
1246 32 : rPos.nContent.GetIndex() );
1247 :
1248 16 : if( rPos.nNode != aInsPos )
1249 : {
1250 0 : aCpyPam.GetMark()->nNode = aInsPos;
1251 0 : aCpyPam.GetMark()->nContent.Assign( aCpyPam.GetCntntNode(sal_False), 0 );
1252 0 : rPos = *aCpyPam.GetMark();
1253 : }
1254 : else
1255 16 : *aCpyPam.GetMark() = rPos;
1256 :
1257 16 : if ( !bAfterTable )
1258 16 : aCpyPam.Move( fnMoveForward, bCanMoveBack ? fnGoCntnt : fnGoNode );
1259 : else
1260 : {
1261 : // Reset the offset to 0 as it was before the insertion
1262 0 : aCpyPam.GetPoint( )->nContent -= aCpyPam.GetPoint( )->nContent;
1263 :
1264 0 : aCpyPam.GetPoint( )->nNode++;
1265 : // If the next node is a start node, then step back: the start node
1266 : // has been copied and needs to be in the selection for the undo
1267 0 : if ( aCpyPam.GetPoint()->nNode.GetNode().IsStartNode() )
1268 0 : aCpyPam.GetPoint( )->nNode--;
1269 :
1270 : }
1271 16 : aCpyPam.Exchange();
1272 :
1273 : // Also copy all bookmarks
1274 16 : if( bCopyBookmarks && getIDocumentMarkAccess()->getMarksCount() )
1275 0 : lcl_CopyBookmarks( rPam, aCpyPam );
1276 :
1277 16 : if( nsRedlineMode_t::REDLINE_DELETE_REDLINES & eOld )
1278 0 : lcl_DeleteRedlines( rPam, aCpyPam );
1279 :
1280 : // If Undo is enabled, store the inserted area
1281 16 : if (pDoc->GetIDocumentUndoRedo().DoesUndo())
1282 : {
1283 0 : pUndo->SetInsertRange( aCpyPam, sal_True, bStartIsTxtNode );
1284 : }
1285 :
1286 16 : if( pCpyRange )
1287 : {
1288 0 : pCpyRange->SetMark();
1289 0 : *pCpyRange->GetPoint() = *aCpyPam.GetPoint();
1290 0 : *pCpyRange->GetMark() = *aCpyPam.GetMark();
1291 : }
1292 :
1293 16 : if ( pNumRuleToPropagate )
1294 : {
1295 : // #i86492# - use <SwDoc::SetNumRule(..)>, because it also handles the <ListId>
1296 : pDoc->SetNumRule( aCpyPam, *pNumRuleToPropagate, false,
1297 0 : aListIdToPropagate, sal_True, true );
1298 : }
1299 :
1300 16 : pDoc->SetRedlineMode_intern( eOld );
1301 16 : pDoc->SetModified();
1302 :
1303 16 : return true;
1304 : }
1305 :
1306 : // Copy method from SwDoc - "copy Flys in Flys"
1307 18 : void SwDoc::CopyWithFlyInFly( const SwNodeRange& rRg, const xub_StrLen nEndContentIndex,
1308 : const SwNodeIndex& rInsPos, sal_Bool bMakeNewFrms,
1309 : sal_Bool bDelRedlines, sal_Bool bCopyFlyAtFly ) const
1310 : {
1311 18 : SwDoc* pDest = rInsPos.GetNode().GetDoc();
1312 :
1313 18 : _SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 );
1314 :
1315 18 : SwNodeIndex aSavePos( rInsPos, -1 );
1316 18 : bool bEndIsEqualEndPos = rInsPos == rRg.aEnd;
1317 18 : GetNodes()._CopyNodes( rRg, rInsPos, bMakeNewFrms, sal_True );
1318 18 : ++aSavePos;
1319 18 : if( bEndIsEqualEndPos )
1320 0 : ((SwNodeIndex&)rRg.aEnd) = aSavePos;
1321 :
1322 18 : aRedlRest.Restore();
1323 :
1324 : #if OSL_DEBUG_LEVEL > 0
1325 : {
1326 : //JP 17.06.99: Bug 66973 - check count only if the selection is in
1327 : // the same section or there's no section, because sections that are
1328 : // not fully selected are not copied.
1329 : const SwSectionNode* pSSectNd = rRg.aStart.GetNode().FindSectionNode();
1330 : SwNodeIndex aTmpI( rRg.aEnd, -1 );
1331 : const SwSectionNode* pESectNd = aTmpI.GetNode().FindSectionNode();
1332 : if( pSSectNd == pESectNd &&
1333 : !rRg.aStart.GetNode().IsSectionNode() &&
1334 : !aTmpI.GetNode().IsEndNode() )
1335 : {
1336 : OSL_ENSURE( rInsPos.GetIndex() - aSavePos.GetIndex() ==
1337 : rRg.aEnd.GetIndex() - rRg.aStart.GetIndex(),
1338 : "An insufficient number of nodes were copied!" );
1339 : }
1340 : }
1341 : #endif
1342 :
1343 : {
1344 18 : ::sw::UndoGuard const undoGuard(pDest->GetIDocumentUndoRedo());
1345 18 : CopyFlyInFlyImpl( rRg, nEndContentIndex, aSavePos, bCopyFlyAtFly );
1346 : }
1347 :
1348 18 : SwNodeRange aCpyRange( aSavePos, rInsPos );
1349 :
1350 : // Also copy all bookmarks
1351 18 : if( getIDocumentMarkAccess()->getMarksCount() )
1352 : {
1353 17 : SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
1354 17 : SwPaM aCpyTmp( aCpyRange.aStart, aCpyRange.aEnd );
1355 :
1356 17 : lcl_CopyBookmarks( aRgTmp, aCpyTmp );
1357 : }
1358 :
1359 18 : if( bDelRedlines && ( nsRedlineMode_t::REDLINE_DELETE_REDLINES & pDest->GetRedlineMode() ))
1360 0 : lcl_DeleteRedlines( rRg, aCpyRange );
1361 :
1362 18 : pDest->GetNodes()._DelDummyNodes( aCpyRange );
1363 18 : }
1364 :
1365 0 : static void lcl_ChainFmts( SwFlyFrmFmt *pSrc, SwFlyFrmFmt *pDest )
1366 : {
1367 0 : SwFmtChain aSrc( pSrc->GetChain() );
1368 0 : if ( !aSrc.GetNext() )
1369 : {
1370 0 : aSrc.SetNext( pDest );
1371 0 : pSrc->SetFmtAttr( aSrc );
1372 : }
1373 0 : SwFmtChain aDest( pDest->GetChain() );
1374 0 : if ( !aDest.GetPrev() )
1375 : {
1376 0 : aDest.SetPrev( pSrc );
1377 0 : pDest->SetFmtAttr( aDest );
1378 0 : }
1379 0 : }
1380 :
1381 194 : void SwDoc::CopyFlyInFlyImpl( const SwNodeRange& rRg,
1382 : const xub_StrLen nEndContentIndex, const SwNodeIndex& rStartIdx,
1383 : const bool bCopyFlyAtFly ) const
1384 : {
1385 : // First collect all Flys, sort them according to their ordering number,
1386 : // and then only copy them. This maintains the ordering numbers (which are only
1387 : // managed in the DrawModel).
1388 194 : SwDoc *const pDest = rStartIdx.GetNode().GetDoc();
1389 194 : ::std::set< _ZSortFly > aSet;
1390 194 : sal_uInt16 nArrLen = GetSpzFrmFmts()->size();
1391 :
1392 259 : for ( sal_uInt16 n = 0; n < nArrLen; ++n )
1393 : {
1394 65 : SwFrmFmt const*const pFmt = (*GetSpzFrmFmts())[n];
1395 65 : SwFmtAnchor const*const pAnchor = &pFmt->GetAnchor();
1396 65 : SwPosition const*const pAPos = pAnchor->GetCntntAnchor();
1397 65 : bool bAtCntnt = (pAnchor->GetAnchorId() == FLY_AT_PARA);
1398 186 : if ( pAPos &&
1399 : ( bAtCntnt ||
1400 33 : (pAnchor->GetAnchorId() == FLY_AT_FLY) ||
1401 33 : (pAnchor->GetAnchorId() == FLY_AT_CHAR)) &&
1402 11 : (( bCopyFlyAtFly && FLY_AT_FLY == pAnchor->GetAnchorId() )
1403 0 : ? rRg.aStart <= pAPos->nNode.GetIndex() + 1
1404 33 : : ( IsRedlineMove()
1405 16 : ? rRg.aStart < pAPos->nNode
1406 16 : : rRg.aStart <= pAPos->nNode )) &&
1407 11 : pAPos->nNode <= rRg.aEnd )
1408 : {
1409 : //frames at the last source node are not always copied:
1410 : //- if the node is empty and is the last node of the document or a table cell
1411 : // or a text frame then tey have to be copied
1412 : //- if the content index in this node is > 0 then paragph and frame bound objects are copied
1413 : //- to-character bound objects are copied if their index is <= nEndContentIndex
1414 6 : bool bAdd = false;
1415 6 : if( pAPos->nNode < rRg.aEnd )
1416 6 : bAdd = true;
1417 6 : if (!bAdd && !IsRedlineMove()) // fdo#40599: not for redline move
1418 : {
1419 0 : bool bEmptyNode = false;
1420 0 : bool bLastNode = false;
1421 : // is the node empty?
1422 0 : const SwNodes& rNodes = pAPos->nNode.GetNodes();
1423 : SwTxtNode* pTxtNode;
1424 0 : if( 0 != ( pTxtNode = pAPos->nNode.GetNode().GetTxtNode() ))
1425 : {
1426 0 : bEmptyNode = !pTxtNode->GetTxt().Len();
1427 0 : if( bEmptyNode )
1428 : {
1429 : //last node information is only necessary to know for the last TextNode
1430 0 : SwNodeIndex aTmp( pAPos->nNode );
1431 0 : ++aTmp;//goto next node
1432 0 : while (aTmp.GetNode().IsEndNode())
1433 : {
1434 0 : if( aTmp == rNodes.GetEndOfContent().GetIndex() )
1435 : {
1436 0 : bLastNode = true;
1437 0 : break;
1438 : }
1439 0 : ++aTmp;
1440 0 : }
1441 : }
1442 : }
1443 0 : bAdd = bLastNode && bEmptyNode;
1444 0 : if( !bAdd )
1445 : {
1446 0 : if( bAtCntnt )
1447 0 : bAdd = nEndContentIndex > 0;
1448 : else
1449 0 : bAdd = pAPos->nContent <= nEndContentIndex;
1450 : }
1451 : }
1452 6 : if( bAdd )
1453 6 : aSet.insert( _ZSortFly( pFmt, pAnchor, nArrLen + aSet.size() ));
1454 : }
1455 : }
1456 :
1457 : // Store all copied (and also the newly created) frames in another array.
1458 : // They are stored as matching the originals, so that we will be later
1459 : // able to build the chains accordingly.
1460 194 : ::std::vector< SwFrmFmt* > aVecSwFrmFmt;
1461 :
1462 200 : for (::std::set< _ZSortFly >::const_iterator it=aSet.begin() ; it != aSet.end(); ++it )
1463 : {
1464 : // #i59964#
1465 : // correct determination of new anchor position
1466 6 : SwFmtAnchor aAnchor( *(*it).GetAnchor() );
1467 6 : SwPosition* pNewPos = (SwPosition*)aAnchor.GetCntntAnchor();
1468 : // for at-paragraph and at-character anchored objects the new anchor
1469 : // position can *not* be determined by the difference of the current
1470 : // anchor position to the start of the copied range, because not
1471 : // complete selected sections in the copied range aren't copied - see
1472 : // method <SwNodes::_CopyNodes(..)>.
1473 : // Thus, the new anchor position in the destination document is found
1474 : // by counting the text nodes.
1475 9 : if ((aAnchor.GetAnchorId() == FLY_AT_PARA) ||
1476 3 : (aAnchor.GetAnchorId() == FLY_AT_CHAR) )
1477 : {
1478 : // First, determine number of anchor text node in the copied range.
1479 : // Note: The anchor text node *have* to be inside the copied range.
1480 6 : sal_uLong nAnchorTxtNdNumInRange( 0L );
1481 6 : bool bAnchorTxtNdFound( false );
1482 6 : SwNodeIndex aIdx( rRg.aStart );
1483 24 : while ( !bAnchorTxtNdFound && aIdx <= rRg.aEnd )
1484 : {
1485 12 : if ( aIdx.GetNode().IsTxtNode() )
1486 : {
1487 6 : ++nAnchorTxtNdNumInRange;
1488 6 : bAnchorTxtNdFound = aAnchor.GetCntntAnchor()->nNode == aIdx;
1489 : }
1490 :
1491 12 : ++aIdx;
1492 : }
1493 6 : if ( !bAnchorTxtNdFound )
1494 : {
1495 : // This case can *not* happen, but to be robust take the first
1496 : // text node in the destination document.
1497 : OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - anchor text node in copied range not found" );
1498 0 : nAnchorTxtNdNumInRange = 1;
1499 : }
1500 : // Second, search corresponding text node in destination document
1501 : // by counting forward from start insert position <rStartIdx> the
1502 : // determined number of text nodes.
1503 6 : aIdx = rStartIdx;
1504 6 : SwNodeIndex aAnchorNdIdx( rStartIdx );
1505 : const SwNode& aEndOfContentNd =
1506 6 : aIdx.GetNode().GetNodes().GetEndOfContent();
1507 36 : while ( nAnchorTxtNdNumInRange > 0 &&
1508 12 : &(aIdx.GetNode()) != &aEndOfContentNd )
1509 : {
1510 12 : if ( aIdx.GetNode().IsTxtNode() )
1511 : {
1512 6 : --nAnchorTxtNdNumInRange;
1513 6 : aAnchorNdIdx = aIdx;
1514 : }
1515 :
1516 12 : ++aIdx;
1517 : }
1518 6 : if ( !aAnchorNdIdx.GetNode().IsTxtNode() )
1519 : {
1520 : // This case can *not* happen, but to be robust take the first
1521 : // text node in the destination document.
1522 : OSL_FAIL( "<SwDoc::_CopyFlyInFly(..)> - found anchor node index isn't a text node" );
1523 0 : aAnchorNdIdx = rStartIdx;
1524 0 : while ( !aAnchorNdIdx.GetNode().IsTxtNode() )
1525 : {
1526 0 : ++aAnchorNdIdx;
1527 : }
1528 : }
1529 : // apply found anchor text node as new anchor position
1530 6 : pNewPos->nNode = aAnchorNdIdx;
1531 : }
1532 : else
1533 : {
1534 0 : long nOffset = pNewPos->nNode.GetIndex() - rRg.aStart.GetIndex();
1535 0 : SwNodeIndex aIdx( rStartIdx, nOffset );
1536 0 : pNewPos->nNode = aIdx;
1537 : }
1538 : // Set the character bound Flys back at the original character
1539 9 : if ((FLY_AT_CHAR == aAnchor.GetAnchorId()) &&
1540 3 : pNewPos->nNode.GetNode().IsTxtNode() )
1541 : {
1542 3 : pNewPos->nContent.Assign( (SwTxtNode*)&pNewPos->nNode.GetNode(),
1543 6 : pNewPos->nContent.GetIndex() );
1544 : }
1545 : else
1546 : {
1547 3 : pNewPos->nContent.Assign( 0, 0 );
1548 : }
1549 :
1550 : // Check recursion: copy content in its own frame, then don't copy it.
1551 6 : bool bMakeCpy = true;
1552 6 : if( pDest == this )
1553 : {
1554 6 : const SwFmtCntnt& rCntnt = (*it).GetFmt()->GetCntnt();
1555 : const SwStartNode* pSNd;
1556 15 : if( rCntnt.GetCntntIdx() &&
1557 3 : 0 != ( pSNd = rCntnt.GetCntntIdx()->GetNode().GetStartNode() ) &&
1558 3 : pSNd->GetIndex() < rStartIdx.GetIndex() &&
1559 3 : rStartIdx.GetIndex() < pSNd->EndOfSectionIndex() )
1560 : {
1561 0 : bMakeCpy = false;
1562 0 : aSet.erase ( it );
1563 : }
1564 : }
1565 :
1566 : // Copy the format and set the new anchor
1567 6 : if( bMakeCpy )
1568 6 : aVecSwFrmFmt.push_back( pDest->CopyLayoutFmt( *(*it).GetFmt(),
1569 12 : aAnchor, false, true ) );
1570 6 : }
1571 :
1572 : // Rebuild as much as possible of all chains that are available in the original,
1573 : OSL_ENSURE( aSet.size() == aVecSwFrmFmt.size(), "Missing new Flys" );
1574 194 : if ( aSet.size() == aVecSwFrmFmt.size() )
1575 : {
1576 194 : size_t n = 0;
1577 200 : for (::std::set< _ZSortFly >::const_iterator nIt=aSet.begin() ; nIt != aSet.end(); ++nIt, ++n )
1578 : {
1579 6 : const SwFrmFmt *pFmtN = (*nIt).GetFmt();
1580 6 : const SwFmtChain &rChain = pFmtN->GetChain();
1581 6 : int nCnt = 0 != rChain.GetPrev();
1582 6 : nCnt += rChain.GetNext() ? 1: 0;
1583 6 : size_t k = 0;
1584 18 : for (::std::set< _ZSortFly >::const_iterator kIt=aSet.begin() ; kIt != aSet.end(); ++kIt, ++k )
1585 : {
1586 12 : const SwFrmFmt *pFmtK = (*kIt).GetFmt();
1587 12 : if ( rChain.GetPrev() == pFmtK )
1588 : {
1589 0 : ::lcl_ChainFmts( dynamic_cast< SwFlyFrmFmt* >(aVecSwFrmFmt[k]),
1590 0 : dynamic_cast< SwFlyFrmFmt* >(aVecSwFrmFmt[n]) );
1591 0 : --nCnt;
1592 : }
1593 12 : else if ( rChain.GetNext() == pFmtK )
1594 : {
1595 0 : ::lcl_ChainFmts( dynamic_cast< SwFlyFrmFmt* >(aVecSwFrmFmt[n]),
1596 0 : dynamic_cast< SwFlyFrmFmt* >(aVecSwFrmFmt[k]) );
1597 0 : --nCnt;
1598 : }
1599 : }
1600 : }
1601 194 : }
1602 194 : }
1603 :
1604 :
1605 :
1606 :
1607 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|