Update ooo320-m1
[ooovba.git] / sw / source / core / docnode / ndcopy.cxx
blobbb9f6ce0e0a4c3f84be92307601356e13a6fa7c1
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ndcopy.cxx,v $
10 * $Revision: 1.34.74.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #define _ZFORLIST_DECLARE_TABLE
36 #include <hintids.hxx>
39 #include <svx/brkitem.hxx>
40 #include <fmtpdsc.hxx>
41 #include <fmtanchr.hxx>
42 #include <fmtcntnt.hxx>
43 #include <doc.hxx>
44 #include <pam.hxx>
45 #include <ndtxt.hxx>
46 #include <fldbas.hxx>
47 #include <swtable.hxx>
48 #include <ddefld.hxx>
49 #include <undobj.hxx>
50 #include <IMark.hxx>
51 #include <mvsave.hxx>
52 #include <cellatr.hxx>
53 #include <swtblfmt.hxx>
54 #include <swddetbl.hxx>
55 #include <docary.hxx>
56 #include <fmtcnct.hxx>
57 #include <redline.hxx>
58 #include <paratr.hxx>
59 #include <pagedesc.hxx>
60 #include <poolfmt.hxx>
61 #include <SwNodeNum.hxx>
62 #ifdef PRODUCT
63 #define CHECK_TABLE(t)
64 #else
65 #ifdef DEBUG
66 #define CHECK_TABLE(t) (t).CheckConsistency();
67 #else
68 #define CHECK_TABLE(t)
69 #endif
70 #endif
72 namespace
75 The lcl_CopyBookmarks function has to copy bookmarks from the source to the destination nodes
76 array. It is called after a call of the _CopyNodes(..) function. But this function does not copy
77 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.
78 The lcl_NonCopyCount function counts the number of these nodes, given the copied pam and a node
79 index inside the pam.
80 rPam is the original source pam, rLastIdx is the last calculated position, rDelCount the number
81 of "non-copy" nodes between rPam.Start() and rLastIdx.
82 nNewIdx is the new position of interest.
85 static void lcl_NonCopyCount( const SwPaM& rPam, SwNodeIndex& rLastIdx, const ULONG nNewIdx, ULONG& rDelCount )
87 ULONG nStart = rPam.Start()->nNode.GetIndex();
88 ULONG nEnd = rPam.End()->nNode.GetIndex();
89 if( rLastIdx.GetIndex() < nNewIdx ) // Moving forward?
91 do // count "non-copy" nodes
93 SwNode& rNode = rLastIdx.GetNode();
94 if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd )
95 || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) )
96 ++rDelCount;
97 rLastIdx++;
99 while( rLastIdx.GetIndex() < nNewIdx );
101 else if( rDelCount ) // optimization: if there are no "non-copy" nodes until now,
102 // no move backward needed
104 while( rLastIdx.GetIndex() > nNewIdx )
106 SwNode& rNode = rLastIdx.GetNode();
107 if( ( rNode.IsSectionNode() && rNode.EndOfSectionIndex() >= nEnd )
108 || ( rNode.IsEndNode() && rNode.StartOfSectionNode()->GetIndex() < nStart ) )
109 --rDelCount;
110 rLastIdx--;
115 static void lcl_SetCpyPos( const SwPosition& rOrigPos,
116 const SwPosition& rOrigStt,
117 const SwPosition& rCpyStt,
118 SwPosition& rChgPos,
119 ULONG nDelCount )
121 ULONG nNdOff = rOrigPos.nNode.GetIndex();
122 nNdOff -= rOrigStt.nNode.GetIndex();
123 nNdOff -= nDelCount;
124 xub_StrLen nCntntPos = rOrigPos.nContent.GetIndex();
126 // --> OD, AMA 2008-07-07 #b6713815#
127 // Always adjust <nNode> at to be changed <SwPosition> instance <rChgPos>
128 rChgPos.nNode = nNdOff + rCpyStt.nNode.GetIndex();
129 if( !nNdOff )
130 // <--
132 // dann nur den Content anpassen
133 if( nCntntPos > rOrigStt.nContent.GetIndex() )
134 nCntntPos = nCntntPos - rOrigStt.nContent.GetIndex();
135 else
136 nCntntPos = 0;
137 nCntntPos = nCntntPos + rCpyStt.nContent.GetIndex();
139 rChgPos.nContent.Assign( rChgPos.nNode.GetNode().GetCntntNode(), nCntntPos );
142 // TODO: use SaveBookmark (from _DelBookmarks)
143 static void lcl_CopyBookmarks(const SwPaM& rPam, SwPaM& rCpyPam)
145 const SwDoc* pSrcDoc = rPam.GetDoc();
146 SwDoc* pDestDoc = rCpyPam.GetDoc();
147 const IDocumentMarkAccess* const pSrcMarkAccess = pSrcDoc->getIDocumentMarkAccess();
148 bool bDoesUndo = pDestDoc->DoesUndo();
149 pDestDoc->DoUndo(false);
151 const SwPosition &rStt = *rPam.Start(), &rEnd = *rPam.End();
152 SwPosition* pCpyStt = rCpyPam.Start();
154 typedef ::std::vector< const ::sw::mark::IMark* > mark_vector_t;
155 mark_vector_t vMarksToCopy;
156 for(IDocumentMarkAccess::const_iterator_t ppMark = pSrcMarkAccess->getMarksBegin();
157 ppMark != pSrcMarkAccess->getMarksEnd();
158 ppMark++)
160 const ::sw::mark::IMark* const pMark = ppMark->get();
161 const SwPosition& rMarkStart = pMark->GetMarkStart();
162 const SwPosition& rMarkEnd = pMark->GetMarkEnd();
163 // only include marks that are in the range and not touching
164 // both start and end
165 bool bIsNotOnBoundary = pMark->IsExpanded()
166 ? (rMarkStart != rStt || rMarkEnd != rEnd) // rMarkStart != rMarkEnd
167 : (rMarkStart != rStt && rMarkEnd != rEnd); // rMarkStart == rMarkEnd
168 if(rMarkStart >= rStt && rMarkEnd <= rEnd && bIsNotOnBoundary)
170 vMarksToCopy.push_back(pMark);
173 // We have to count the "non-copied" nodes..
174 SwNodeIndex aCorrIdx(rStt.nNode);
175 ULONG nDelCount = 0;
176 for(mark_vector_t::const_iterator ppMark = vMarksToCopy.begin();
177 ppMark != vMarksToCopy.end();
178 ++ppMark)
180 const ::sw::mark::IMark* const pMark = *ppMark;
181 SwPaM aTmpPam(*pCpyStt);
182 lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetMarkPos().nNode.GetIndex(), nDelCount);
183 lcl_SetCpyPos( pMark->GetMarkPos(), rStt, *pCpyStt, *aTmpPam.GetPoint(), nDelCount);
184 if(pMark->IsExpanded())
186 aTmpPam.SetMark();
187 lcl_NonCopyCount(rPam, aCorrIdx, pMark->GetOtherMarkPos().nNode.GetIndex(), nDelCount);
188 lcl_SetCpyPos(pMark->GetOtherMarkPos(), rStt, *pCpyStt, *aTmpPam.GetMark(), nDelCount);
191 ::sw::mark::IMark* const pNewMark = pDestDoc->getIDocumentMarkAccess()->makeMark(
192 aTmpPam,
193 pMark->GetName(),
194 IDocumentMarkAccess::GetType(*pMark));
195 // Explicitly try to get exactly the same name as in the source
196 // because NavigatorReminders, DdeBookmarks etc. ignore the proposed name
197 pDestDoc->getIDocumentMarkAccess()->renameMark(pNewMark, pMark->GetName());
198 ::sw::mark::IBookmark* const pNewBookmark =
199 dynamic_cast< ::sw::mark::IBookmark* const >(pNewMark);
200 if(pNewBookmark) /* copying additional attributes for bookmarks */
202 const ::sw::mark::IBookmark* const pOldBookmark = dynamic_cast< const ::sw::mark::IBookmark* >(pMark);
203 pNewBookmark->SetKeyCode(pOldBookmark->GetKeyCode());
204 pNewBookmark->SetShortName(pOldBookmark->GetShortName());
206 ::sfx2::Metadatable const*const pMetadatable(
207 dynamic_cast< ::sfx2::Metadatable const* >(pMark));
208 ::sfx2::Metadatable *const pNewMetadatable(
209 dynamic_cast< ::sfx2::Metadatable * >(pNewMark));
210 if (pMetadatable && pNewMetadatable)
212 pNewMetadatable->RegisterAsCopyOf(*pMetadatable);
215 pDestDoc->DoUndo(bDoesUndo);
219 // Struktur fuer das Mappen von alten und neuen Frame-Formaten an den
220 // Boxen und Lines einer Tabelle
222 struct _MapTblFrmFmt
224 const SwFrmFmt *pOld, *pNew;
225 _MapTblFrmFmt( const SwFrmFmt *pOldFmt, const SwFrmFmt*pNewFmt )
226 : pOld( pOldFmt ), pNew( pNewFmt )
230 SV_DECL_VARARR( _MapTblFrmFmts, _MapTblFrmFmt, 0, 10 )
231 SV_IMPL_VARARR( _MapTblFrmFmts, _MapTblFrmFmt );
233 SwCntntNode* SwTxtNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
235 // the Copy-Textnode is the Node with the Text, the Copy-Attrnode is the
236 // node with the collection and hard attributes. Normally ist the same
237 // node, but if insert a glossary without formatting, then the Attrnode
238 // is the prev node of the destionation position in dest. document.
239 SwTxtNode* pCpyTxtNd = (SwTxtNode*)this;
240 SwTxtNode* pCpyAttrNd = pCpyTxtNd;
242 // kopiere die Formate in das andere Dokument:
243 SwTxtFmtColl* pColl = 0;
244 if( pDoc->IsInsOnlyTextGlossary() )
246 SwNodeIndex aIdx( rIdx, -1 );
247 if( aIdx.GetNode().IsTxtNode() )
249 pCpyAttrNd = aIdx.GetNode().GetTxtNode();
250 pColl = &pCpyAttrNd->GetTxtColl()->GetNextTxtFmtColl();
253 if( !pColl )
254 pColl = pDoc->CopyTxtColl( *GetTxtColl() );
256 SwTxtNode* pTxtNd = pDoc->GetNodes().MakeTxtNode( rIdx, pColl );
258 // METADATA: register copy
259 pTxtNd->RegisterAsCopyOf(*pCpyTxtNd);
261 // kopiere Attribute/Text
262 if( !pCpyAttrNd->HasSwAttrSet() )
263 // wurde ein AttrSet fuer die Numerierung angelegt, so loesche diesen!
264 pCpyAttrNd->ResetAllAttr();
266 // if Copy-Textnode unequal to Copy-Attrnode, then copy first
267 // the attributes into the new Node.
268 if( pCpyAttrNd != pCpyTxtNd )
270 pCpyAttrNd->CopyAttr( pTxtNd, 0, 0 );
271 if( pCpyAttrNd->HasSwAttrSet() )
273 SwAttrSet aSet( *pCpyAttrNd->GetpSwAttrSet() );
274 aSet.ClearItem( RES_PAGEDESC );
275 aSet.ClearItem( RES_BREAK );
276 aSet.CopyToModify( *pTxtNd );
280 // ??? reicht das ??? was ist mit PostIts/Feldern/FeldTypen ???
281 // --> OD 2008-11-18 #i96213# - force copy of all attributes
282 pCpyTxtNd->CopyText( pTxtNd, SwIndex( pCpyTxtNd ),
283 pCpyTxtNd->GetTxt().Len(), true );
284 // <--
286 //FEATURE::CONDCOLL
287 if( RES_CONDTXTFMTCOLL == pColl->Which() )
288 pTxtNd->ChkCondColl();
289 //FEATURE::CONDCOLL
291 return pTxtNd;
295 BOOL lcl_SrchNew( const _MapTblFrmFmt& rMap, void * pPara )
297 if( rMap.pOld != *(const SwFrmFmt**)pPara )
298 return TRUE;
299 *((const SwFrmFmt**)pPara) = rMap.pNew;
300 return FALSE; // abbrechen, Pointer gefunden
304 struct _CopyTable
306 SwDoc* pDoc;
307 ULONG nOldTblSttIdx;
308 _MapTblFrmFmts& rMapArr;
309 SwTableLine* pInsLine;
310 SwTableBox* pInsBox;
311 SwTableNode *pTblNd;
312 const SwTable *pOldTable;
314 _CopyTable( SwDoc* pDc, _MapTblFrmFmts& rArr, ULONG nOldStt,
315 SwTableNode& rTblNd, const SwTable* pOldTbl )
316 : pDoc(pDc), nOldTblSttIdx(nOldStt), rMapArr(rArr),
317 pInsLine(0), pInsBox(0), pTblNd(&rTblNd), pOldTable( pOldTbl )
321 BOOL lcl_CopyTblBox( const SwTableBox*& rpBox, void* pPara );
323 BOOL lcl_CopyTblLine( const SwTableLine*& rpLine, void* pPara );
325 BOOL lcl_CopyTblBox( const SwTableBox*& rpBox, void* pPara )
327 _CopyTable* pCT = (_CopyTable*)pPara;
329 SwTableBoxFmt* pBoxFmt = (SwTableBoxFmt*)rpBox->GetFrmFmt();
330 pCT->rMapArr.ForEach( lcl_SrchNew, &pBoxFmt );
331 if( pBoxFmt == rpBox->GetFrmFmt() ) // ein neues anlegen ??
333 const SfxPoolItem* pItem;
334 if( SFX_ITEM_SET == pBoxFmt->GetItemState( RES_BOXATR_FORMULA, FALSE,
335 &pItem ) && ((SwTblBoxFormula*)pItem)->IsIntrnlName() )
337 ((SwTblBoxFormula*)pItem)->PtrToBoxNm( pCT->pOldTable );
340 pBoxFmt = pCT->pDoc->MakeTableBoxFmt();
341 pBoxFmt->CopyAttrs( *rpBox->GetFrmFmt() );
343 if( rpBox->GetSttIdx() )
345 SvNumberFormatter* pN = pCT->pDoc->GetNumberFormatter( FALSE );
346 if( pN && pN->HasMergeFmtTbl() && SFX_ITEM_SET == pBoxFmt->
347 GetItemState( RES_BOXATR_FORMAT, FALSE, &pItem ) )
349 ULONG nOldIdx = ((SwTblBoxNumFormat*)pItem)->GetValue();
350 ULONG nNewIdx = pN->GetMergeFmtIndex( nOldIdx );
351 if( nNewIdx != nOldIdx )
352 pBoxFmt->SetFmtAttr( SwTblBoxNumFormat( nNewIdx ));
357 pCT->rMapArr.Insert( _MapTblFrmFmt( rpBox->GetFrmFmt(), pBoxFmt ),
358 pCT->rMapArr.Count() );
361 USHORT nLines = rpBox->GetTabLines().Count();
362 SwTableBox* pNewBox;
363 if( nLines )
364 pNewBox = new SwTableBox( pBoxFmt, nLines, pCT->pInsLine );
365 else
367 SwNodeIndex aNewIdx( *pCT->pTblNd,
368 rpBox->GetSttIdx() - pCT->nOldTblSttIdx );
369 ASSERT( aNewIdx.GetNode().IsStartNode(), "Index nicht auf einem StartNode" );
370 pNewBox = new SwTableBox( pBoxFmt, aNewIdx, pCT->pInsLine );
371 pNewBox->setRowSpan( rpBox->getRowSpan() );
374 pCT->pInsLine->GetTabBoxes().C40_INSERT( SwTableBox, pNewBox,
375 pCT->pInsLine->GetTabBoxes().Count() );
377 if( nLines )
379 _CopyTable aPara( *pCT );
380 aPara.pInsBox = pNewBox;
381 ((SwTableBox*)rpBox)->GetTabLines().ForEach( &lcl_CopyTblLine, &aPara );
383 else if( pNewBox->IsInHeadline( &pCT->pTblNd->GetTable() ))
384 // in der HeadLine sind die Absaetze mit BedingtenVorlage anzupassen
385 pNewBox->GetSttNd()->CheckSectionCondColl();
386 return TRUE;
389 BOOL lcl_CopyTblLine( const SwTableLine*& rpLine, void* pPara )
391 _CopyTable* pCT = (_CopyTable*)pPara;
392 SwTableLineFmt* pLineFmt = (SwTableLineFmt*)rpLine->GetFrmFmt();
393 pCT->rMapArr.ForEach( lcl_SrchNew, &pLineFmt );
394 if( pLineFmt == rpLine->GetFrmFmt() ) // ein neues anlegen ??
396 pLineFmt = pCT->pDoc->MakeTableLineFmt();
397 pLineFmt->CopyAttrs( *rpLine->GetFrmFmt() );
398 pCT->rMapArr.Insert( _MapTblFrmFmt( rpLine->GetFrmFmt(), pLineFmt ),
399 pCT->rMapArr.Count());
401 SwTableLine* pNewLine = new SwTableLine( pLineFmt,
402 rpLine->GetTabBoxes().Count(), pCT->pInsBox );
403 // die neue Zeile in die Tabelle eintragen
404 if( pCT->pInsBox )
406 pCT->pInsBox->GetTabLines().C40_INSERT( SwTableLine, pNewLine,
407 pCT->pInsBox->GetTabLines().Count() );
409 else
411 pCT->pTblNd->GetTable().GetTabLines().C40_INSERT( SwTableLine, pNewLine,
412 pCT->pTblNd->GetTable().GetTabLines().Count() );
414 pCT->pInsLine = pNewLine;
415 ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &lcl_CopyTblBox, pCT );
416 return TRUE;
419 SwTableNode* SwTableNode::MakeCopy( SwDoc* pDoc, const SwNodeIndex& rIdx ) const
421 // in welchen Array steht ich denn Nodes, UndoNodes ??
422 SwNodes& rNds = (SwNodes&)GetNodes();
425 // nicht in Fussnoten kopieren !!
427 !! Mal ohne Frames
428 SwCntntNode* pCNd = pDoc->GetNodes()[ rIdx ]->GetCntntNode();
429 SwFrm* pFrm;
430 if( (pCNd && 0 != ( pFrm = pCNd->GetFrm()))
431 ? pFrm->FindFtnFrm()
432 : rIdx < pDoc->GetNodes().EndOfInserts &&
433 pDoc->GetNodes()[pDoc->GetNodes().EndOfInserts]->StartOfSection()
434 < rIdx )
436 if( rIdx < pDoc->GetNodes().GetEndOfInserts().GetIndex() &&
437 rIdx >= pDoc->GetNodes().GetEndOfInserts().StartOfSectionIndex() )
438 return 0;
441 // das TableFrmFmt kopieren
442 String sTblName( GetTable().GetFrmFmt()->GetName() );
443 if( !pDoc->IsCopyIsMove() )
445 const SwFrmFmts& rTblFmts = *pDoc->GetTblFrmFmts();
446 for( USHORT n = rTblFmts.Count(); n; )
447 if( rTblFmts[ --n ]->GetName() == sTblName )
449 sTblName = pDoc->GetUniqueTblName();
450 break;
454 SwFrmFmt* pTblFmt = pDoc->MakeTblFrmFmt( sTblName, pDoc->GetDfltFrmFmt() );
455 pTblFmt->CopyAttrs( *GetTable().GetFrmFmt() );
456 SwTableNode* pTblNd = new SwTableNode( rIdx );
457 SwEndNode* pEndNd = new SwEndNode( rIdx, *pTblNd );
458 SwNodeIndex aInsPos( *pEndNd );
460 SwTable& rTbl = (SwTable&)pTblNd->GetTable();
461 pTblFmt->Add( &rTbl ); // das Frame-Format setzen
463 rTbl.SetRowsToRepeat( GetTable().GetRowsToRepeat() );
464 rTbl.SetTblChgMode( GetTable().GetTblChgMode() );
465 rTbl.SetTableModel( GetTable().IsNewModel() );
467 SwDDEFieldType* pDDEType = 0;
468 if( IS_TYPE( SwDDETable, &GetTable() ))
470 // es wird eine DDE-Tabelle kopiert
471 // ist im neuen Dokument ueberhaupt der FeldTyp vorhanden ?
472 pDDEType = ((SwDDETable&)GetTable()).GetDDEFldType();
473 if( pDDEType->IsDeleted() )
474 pDoc->InsDeletedFldType( *pDDEType );
475 else
476 pDDEType = (SwDDEFieldType*)pDoc->InsertFldType( *pDDEType );
477 ASSERT( pDDEType, "unbekannter FieldType" );
479 // tauschen am Node den Tabellen-Pointer aus
480 SwDDETable* pNewTable = new SwDDETable( pTblNd->GetTable(), pDDEType );
481 pTblNd->SetNewTable( pNewTable, FALSE );
483 // dann kopiere erstmal den Inhalt der Tabelle, die Zuordnung der
484 // Boxen/Lines und das anlegen der Frames erfolgt spaeter
485 SwNodeRange aRg( *this, +1, *EndOfSectionNode() ); // (wo stehe in denn nun ??)
487 // If there is a table in this table, the table format for the outer table
488 // does not seem to be used, because the table does not have any contents yet
489 // (see IsUsed). Therefore the inner table gets the same name as the outer table.
490 // We have to make sure that the table node of the SwTable is accessible, even
491 // without any content in aSortCntBoxes. #i26629#
492 pTblNd->GetTable().SetTableNode( pTblNd );
493 rNds._Copy( aRg, aInsPos, FALSE );
494 pTblNd->GetTable().SetTableNode( 0 );
496 // Sonderbehandlung fuer eine einzelne Box
497 if( 1 == GetTable().GetTabSortBoxes().Count() )
499 aRg.aStart.Assign( *pTblNd, 1 );
500 aRg.aEnd.Assign( *pTblNd->EndOfSectionNode() );
501 pDoc->GetNodes().SectionDown( &aRg, SwTableBoxStartNode );
504 // loesche alle Frames vom kopierten Bereich, diese werden beim
505 // erzeugen des TableFrames angelegt !
506 pTblNd->DelFrms();
508 _MapTblFrmFmts aMapArr;
509 _CopyTable aPara( pDoc, aMapArr, GetIndex(), *pTblNd, &GetTable() );
511 ((SwTable&)GetTable()).GetTabLines().ForEach( &lcl_CopyTblLine, &aPara );
513 if( pDDEType )
514 pDDEType->IncRefCnt();
516 CHECK_TABLE( GetTable() );
517 return pTblNd;
520 void SwTxtNode::CopyCollFmt( SwTxtNode& rDestNd )
522 // kopiere die Formate in das andere Dokument:
524 // Sonderbehandlung fuer PageBreak/PageDesc/ColBrk
525 SwDoc* pDestDoc = rDestNd.GetDoc();
526 SwAttrSet aPgBrkSet( pDestDoc->GetAttrPool(), aBreakSetRange );
527 const SwAttrSet* pSet;
529 if( 0 != ( pSet = rDestNd.GetpSwAttrSet() ) )
531 // Sonderbehandlung fuer unsere Break-Attribute
532 const SfxPoolItem* pAttr;
533 if( SFX_ITEM_SET == pSet->GetItemState( RES_BREAK, FALSE, &pAttr ) )
534 aPgBrkSet.Put( *pAttr );
536 if( SFX_ITEM_SET == pSet->GetItemState( RES_PAGEDESC, FALSE, &pAttr ) )
537 aPgBrkSet.Put( *pAttr );
540 rDestNd.ChgFmtColl( pDestDoc->CopyTxtColl( *GetTxtColl() ));
541 if( 0 != ( pSet = GetpSwAttrSet() ) )
542 pSet->CopyToModify( rDestNd );
544 if( aPgBrkSet.Count() )
545 rDestNd.SetAttr( aPgBrkSet );
549 // ----- Copy-Methode vom SwDoc ------
551 // verhinder das Kopieren in Fly's, die im Bereich verankert sind.
552 BOOL lcl_ChkFlyFly( SwDoc* pDoc, ULONG nSttNd, ULONG nEndNd,
553 ULONG nInsNd )
555 const SwFrmFmt* pFmt;
556 const SwFmtAnchor* pAnchor;
557 const SwPosition* pAPos;
558 const SwSpzFrmFmts& rFrmFmtTbl = *pDoc->GetSpzFrmFmts();
560 for( USHORT n = 0; n < rFrmFmtTbl.Count(); ++n )
562 pFmt = rFrmFmtTbl[n];
563 pAnchor = &pFmt->GetAnchor();
564 if( 0 != ( pAPos = pAnchor->GetCntntAnchor()) &&
565 ( FLY_IN_CNTNT == pAnchor->GetAnchorId() ||
566 FLY_AUTO_CNTNT == pAnchor->GetAnchorId() ||
567 FLY_AT_FLY == pAnchor->GetAnchorId() ||
568 FLY_AT_CNTNT == pAnchor->GetAnchorId() ) &&
569 nSttNd <= pAPos->nNode.GetIndex() &&
570 pAPos->nNode.GetIndex() < nEndNd )
572 const SwFmtCntnt& rCntnt = pFmt->GetCntnt();
573 SwStartNode* pSNd;
574 if( !rCntnt.GetCntntIdx() ||
575 0 == ( pSNd = rCntnt.GetCntntIdx()->GetNode().GetStartNode() ))
576 continue;
578 if( pSNd->GetIndex() < nInsNd &&
579 nInsNd < pSNd->EndOfSectionIndex() )
580 return TRUE; // nicht kopieren !!
582 if( lcl_ChkFlyFly( pDoc, pSNd->GetIndex(),
583 pSNd->EndOfSectionIndex(), nInsNd ) )
584 return TRUE; // nicht kopieren !!
588 return FALSE;
591 void lcl_DeleteRedlines( const SwPaM& rPam, SwPaM& rCpyPam )
593 const SwDoc* pSrcDoc = rPam.GetDoc();
594 const SwRedlineTbl& rTbl = pSrcDoc->GetRedlineTbl();
595 if( rTbl.Count() )
597 SwDoc* pDestDoc = rCpyPam.GetDoc();
598 SwPosition* pCpyStt = rCpyPam.Start(), *pCpyEnd = rCpyPam.End();
599 SwPaM* pDelPam = 0;
600 const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
601 // We have to count the "non-copied" nodes
602 ULONG nDelCount = 0;
603 SwNodeIndex aCorrIdx( pStt->nNode );
605 USHORT n = 0;
606 pSrcDoc->GetRedline( *pStt, &n );
607 for( ; n < rTbl.Count(); ++n )
609 const SwRedline* pRedl = rTbl[ n ];
610 if( nsRedlineType_t::REDLINE_DELETE == pRedl->GetType() && pRedl->IsVisible() )
612 const SwPosition *pRStt = pRedl->Start(), *pREnd = pRedl->End();
614 SwComparePosition eCmpPos = ComparePosition( *pStt, *pEnd, *pRStt, *pREnd );
615 switch( eCmpPos )
617 case POS_COLLIDE_END:
618 case POS_BEFORE: // Pos1 liegt vor Pos2
619 break;
621 case POS_COLLIDE_START:
622 case POS_BEHIND: // Pos1 liegt hinter Pos2
623 n = rTbl.Count();
624 break;
626 default:
628 pDelPam = new SwPaM( *pCpyStt, pDelPam );
629 if( *pStt < *pRStt )
631 lcl_NonCopyCount( rPam, aCorrIdx, pRStt->nNode.GetIndex(), nDelCount );
632 lcl_SetCpyPos( *pRStt, *pStt, *pCpyStt,
633 *pDelPam->GetPoint(), nDelCount );
635 pDelPam->SetMark();
637 if( *pEnd < *pREnd )
638 *pDelPam->GetPoint() = *pCpyEnd;
639 else
641 lcl_NonCopyCount( rPam, aCorrIdx, pREnd->nNode.GetIndex(), nDelCount );
642 lcl_SetCpyPos( *pREnd, *pStt, *pCpyStt,
643 *pDelPam->GetPoint(), nDelCount );
650 if( pDelPam )
652 RedlineMode_t eOld = pDestDoc->GetRedlineMode();
653 pDestDoc->SetRedlineMode_intern( (RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
655 BOOL bDoesUndo = pDestDoc->DoesUndo();
656 pDestDoc->DoUndo( FALSE );
658 do {
659 pDestDoc->DeleteAndJoin( *(SwPaM*)pDelPam->GetNext() );
660 if( pDelPam->GetNext() == pDelPam )
661 break;
662 delete pDelPam->GetNext();
663 } while( TRUE );
664 delete pDelPam;
666 pDestDoc->DoUndo( bDoesUndo );
667 pDestDoc->SetRedlineMode_intern( eOld );
672 void lcl_DeleteRedlines( const SwNodeRange& rRg, SwNodeRange& rCpyRg )
674 SwDoc* pSrcDoc = rRg.aStart.GetNode().GetDoc();
675 if( pSrcDoc->GetRedlineTbl().Count() )
677 SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
678 SwPaM aCpyTmp( rCpyRg.aStart, rCpyRg.aEnd );
679 lcl_DeleteRedlines( aRgTmp, aCpyTmp );
683 // Kopieren eines Bereiches im oder in ein anderes Dokument !
685 bool
686 SwDoc::CopyRange( SwPaM& rPam, SwPosition& rPos, const bool bCopyAll ) const
688 const SwPosition *pStt = rPam.Start(), *pEnd = rPam.End();
690 SwDoc* pDoc = rPos.nNode.GetNode().GetDoc();
691 bool bColumnSel = pDoc->IsClipBoard() && pDoc->IsColumnSelection();
693 // kein Copy abfangen.
694 if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) )
695 return false;
697 // verhinder das Kopieren in Fly's, die im Bereich verankert sind.
698 if( pDoc == this )
700 // Start-/EndNode noch korrigieren
701 ULONG nStt = pStt->nNode.GetIndex(),
702 nEnd = pEnd->nNode.GetIndex(),
703 nDiff = nEnd - nStt +1;
704 SwNode* pNd = GetNodes()[ nStt ];
705 if( pNd->IsCntntNode() && pStt->nContent.GetIndex() )
706 ++nStt, --nDiff;
707 if( (pNd = GetNodes()[ nEnd ])->IsCntntNode() &&
708 ((SwCntntNode*)pNd)->Len() != pEnd->nContent.GetIndex() )
709 --nEnd, --nDiff;
710 if( nDiff &&
711 lcl_ChkFlyFly( pDoc, nStt, nEnd, rPos.nNode.GetIndex() ) )
713 return false;
717 SwPaM* pRedlineRange = 0;
718 if( pDoc->IsRedlineOn() ||
719 (!pDoc->IsIgnoreRedline() && pDoc->GetRedlineTbl().Count() ) )
720 pRedlineRange = new SwPaM( rPos );
722 RedlineMode_t eOld = pDoc->GetRedlineMode();
724 bool bRet = false;
726 if( pDoc != this )
727 { // ordinary copy
728 bRet = CopyImpl( rPam, rPos, true, bCopyAll, pRedlineRange );
730 // Copy in sich selbst (ueber mehrere Nodes wird hier gesondert
731 // behandelt; in einem TextNode wird normal behandelt)
732 else if( ! ( *pStt <= rPos && rPos < *pEnd &&
733 ( pStt->nNode != pEnd->nNode ||
734 !pStt->nNode.GetNode().IsTxtNode() )) )
735 { // ordinary copy
736 bRet = CopyImpl( rPam, rPos, true, bCopyAll, pRedlineRange );
738 else
740 ASSERT( this == pDoc, " falscher Copy-Zweig!" );
741 ASSERT(false, "mst: i thought this could be dead code;"
742 "please tell me what you did to get here!");
743 pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
745 BOOL bDoUndo = pDoc->DoesUndo();
746 pDoc->DoUndo( FALSE ); // Auf jedenfall Undo abschalten
747 // dann kopiere den Bereich im unteren DokumentBereich,
748 // (mit Start/End-Nodes geklammert) und verschiebe diese
749 // dann an die gewuenschte Stelle.
751 SwUndoCpyDoc* pUndo = 0;
752 SwPaM aPam( rPos ); // UndoBereich sichern
753 if( bDoUndo )
755 pDoc->ClearRedo();
756 pUndo = new SwUndoCpyDoc( aPam );
759 SwStartNode* pSttNd = pDoc->GetNodes().MakeEmptySection(
760 SwNodeIndex( GetNodes().GetEndOfAutotext() ));
761 aPam.GetPoint()->nNode = *pSttNd->EndOfSectionNode();
762 // copy without Frames
763 pDoc->CopyImpl( rPam, *aPam.GetPoint(), false, bCopyAll, 0 );
765 aPam.GetPoint()->nNode = pDoc->GetNodes().GetEndOfAutotext();
766 aPam.SetMark();
767 SwCntntNode* pNode = pDoc->GetNodes().GoPrevious( &aPam.GetMark()->nNode );
768 pNode->MakeEndIndex( &aPam.GetMark()->nContent );
770 aPam.GetPoint()->nNode = *aPam.GetNode()->StartOfSectionNode();
771 pNode = pDoc->GetNodes().GoNext( &aPam.GetPoint()->nNode );
772 pNode->MakeStartIndex( &aPam.GetPoint()->nContent );
773 // move to desired position
774 pDoc->MoveRange( aPam, rPos, DOC_MOVEDEFAULT );
776 pNode = aPam.GetCntntNode();
777 *aPam.GetPoint() = rPos; // Cursor umsetzen fuers Undo !
778 aPam.SetMark(); // auch den Mark umsetzen !!
779 aPam.DeleteMark(); // aber keinen Bereich makieren !!
780 pDoc->DeleteSection( pNode ); // Bereich wieder loeschen
782 // falls Undo eingeschaltet ist, so speicher den eingefuegten Bereich
783 pDoc->DoUndo( bDoUndo );
784 if( bDoUndo )
786 pUndo->SetInsertRange( aPam );
787 pDoc->AppendUndo( pUndo );
790 if( pRedlineRange )
792 pRedlineRange->SetMark();
793 *pRedlineRange->GetPoint() = *aPam.GetPoint();
794 *pRedlineRange->GetMark() = *aPam.GetMark();
797 pDoc->SetModified();
798 bRet = true;
801 pDoc->SetRedlineMode_intern( eOld );
802 if( pRedlineRange )
804 if( pDoc->IsRedlineOn() )
805 pDoc->AppendRedline( new SwRedline( nsRedlineType_t::REDLINE_INSERT, *pRedlineRange ), true);
806 else
807 pDoc->SplitRedline( *pRedlineRange );
808 delete pRedlineRange;
811 return bRet;
814 // Kopieren eines Bereiches im oder in ein anderes Dokument !
815 // Die Position darf nicht im Bereich liegen !!
817 bool lcl_MarksWholeNode(const SwPaM & rPam)
819 bool bResult = false;
820 const SwPosition* pStt = rPam.Start();
821 const SwPosition* pEnd = rPam.End();
823 if (NULL != pStt && NULL != pEnd)
825 const SwTxtNode* pSttNd = pStt->nNode.GetNode().GetTxtNode();
826 const SwTxtNode* pEndNd = pEnd->nNode.GetNode().GetTxtNode();
828 if (NULL != pSttNd && NULL != pEndNd &&
829 pStt->nContent.GetIndex() == 0 &&
830 pEnd->nContent.GetIndex() == pEndNd->Len())
832 bResult = true;
836 return bResult;
839 // --> OD 2009-08-25 #i86492#
840 bool lcl_ContainsOnlyParagraphsInList( const SwPaM& rPam )
842 bool bRet = false;
844 const SwTxtNode* pTxtNd = rPam.Start()->nNode.GetNode().GetTxtNode();
845 const SwTxtNode* pEndTxtNd = rPam.End()->nNode.GetNode().GetTxtNode();
846 if ( pTxtNd && pTxtNd->IsInList() &&
847 pEndTxtNd && pEndTxtNd->IsInList() )
849 bRet = true;
850 SwNodeIndex aIdx(rPam.Start()->nNode);
854 aIdx++;
855 pTxtNd = aIdx.GetNode().GetTxtNode();
857 if ( !pTxtNd || !pTxtNd->IsInList() )
859 bRet = false;
860 break;
862 } while ( pTxtNd && pTxtNd != pEndTxtNd );
866 return bRet;
868 // <--
870 bool SwDoc::CopyImpl( SwPaM& rPam, SwPosition& rPos,
871 const bool bMakeNewFrms, const bool bCopyAll,
872 SwPaM *const pCpyRange ) const
874 SwDoc* pDoc = rPos.nNode.GetNode().GetDoc();
875 const bool bColumnSel = pDoc->IsClipBoard() && pDoc->IsColumnSelection();
877 SwPosition* pStt = rPam.Start();
878 SwPosition* pEnd = rPam.End();
880 // kein Copy abfangen.
881 if( !rPam.HasMark() || ( *pStt >= *pEnd && !bColumnSel ) ||
882 //JP 29.6.2001: 88963 - dont copy if inspos is in region of start to end
883 //JP 15.11.2001: don't test inclusive the end, ever exclusive
884 ( pDoc == this && *pStt <= rPos && rPos < *pEnd ))
886 return false;
889 const bool bEndEqualIns = pDoc == this && rPos == *pEnd;
891 // falls Undo eingeschaltet, erzeuge das UndoCopy-Objekt
892 SwUndoCpyDoc* pUndo = 0;
893 SwPaM aCpyPam( rPos );
895 SwTblNumFmtMerge aTNFM( *this, *pDoc );
897 if( pDoc->DoesUndo() )
899 pDoc->ClearRedo();
900 pUndo = new SwUndoCpyDoc( aCpyPam );
901 pDoc->AppendUndo( pUndo );
904 RedlineMode_t eOld = pDoc->GetRedlineMode();
905 pDoc->SetRedlineMode_intern((RedlineMode_t)(eOld | nsRedlineMode_t::REDLINE_IGNORE));
908 // bewege den Pam von der Insert-Position ein zurueck, dadurch wird
909 // die Position nicht "verschoben"
910 aCpyPam.SetMark();
911 BOOL bCanMoveBack = aCpyPam.Move( fnMoveBackward, fnGoCntnt );
912 if( !bCanMoveBack )
913 aCpyPam.GetPoint()->nNode--;
915 SwNodeRange aRg( pStt->nNode, pEnd->nNode );
916 SwNodeIndex aInsPos( rPos.nNode );
917 const bool bOneNode = pStt->nNode == pEnd->nNode;
918 SwTxtNode* pSttTxtNd = pStt->nNode.GetNode().GetTxtNode();
919 SwTxtNode* pEndTxtNd = pEnd->nNode.GetNode().GetTxtNode();
920 SwTxtNode* pDestTxtNd = aInsPos.GetNode().GetTxtNode();
921 bool bCopyCollFmt = !pDoc->IsInsOnlyTextGlossary() &&
922 ( ( pDestTxtNd && !pDestTxtNd->GetTxt().Len() ) ||
923 ( !bOneNode && !rPos.nContent.GetIndex() ) );
924 bool bCopyBookmarks = true;
925 BOOL bStartIsTxtNode = 0 != pSttTxtNd;
927 // --> OD 2009-08-25 #i86492#
928 // Correct the search for a previous list:
929 // First search for non-outline numbering list. Then search for non-outline
930 // bullet list.
931 // Keep also the <ListId> value for possible propagation.
932 String aListIdToPropagate;
933 const SwNumRule* pNumRuleToPropagate =
934 pDoc->SearchNumRule( rPos, false, true, false, 0, aListIdToPropagate, true );
935 if ( !pNumRuleToPropagate )
937 pNumRuleToPropagate =
938 pDoc->SearchNumRule( rPos, false, false, false, 0, aListIdToPropagate, true );
940 // <--
941 // --> OD 2009-08-25 #i86492#
942 // Do not propagate previous found list, if
943 // - destination is an empty paragraph which is not in a list and
944 // - source contains at least one paragraph which is not in a list
945 if ( pNumRuleToPropagate &&
946 pDestTxtNd && !pDestTxtNd->GetTxt().Len() && !pDestTxtNd->IsInList() &&
947 !lcl_ContainsOnlyParagraphsInList( rPam ) )
949 pNumRuleToPropagate = 0;
951 // <--
953 // Block, damit aus diesem gesprungen werden kann !!
954 do {
955 if( pSttTxtNd )
957 // den Anfang nicht komplett kopieren ?
958 if( !bCopyCollFmt || bColumnSel || pStt->nContent.GetIndex() )
960 SwIndex aDestIdx( rPos.nContent );
961 BOOL bCopyOk = FALSE;
962 if( !pDestTxtNd )
964 if( pStt->nContent.GetIndex() || bOneNode )
965 pDestTxtNd = pDoc->GetNodes().MakeTxtNode( aInsPos,
966 pDoc->GetTxtCollFromPool(RES_POOLCOLL_STANDARD));
967 else
969 pDestTxtNd = static_cast<SwTxtNode*>(pSttTxtNd->MakeCopy( pDoc, aInsPos ));
970 bCopyOk = TRUE;
972 aDestIdx.Assign( pDestTxtNd, 0 );
973 bCopyCollFmt = true;
975 else if( !bOneNode || bColumnSel )
977 xub_StrLen nCntntEnd = pEnd->nContent.GetIndex();
978 BOOL bDoesUndo = pDoc->DoesUndo();
979 pDoc->DoUndo( FALSE );
980 pDoc->SplitNode( rPos, false );
981 pDoc->DoUndo( bDoesUndo );
983 if( bCanMoveBack && rPos == *aCpyPam.GetPoint() )
985 // nach dem SplitNode, den CpyPam wieder richtig aufspannen
986 aCpyPam.Move( fnMoveBackward, fnGoCntnt );
987 aCpyPam.Move( fnMoveBackward, fnGoCntnt );
990 pDestTxtNd = pDoc->GetNodes()[ aInsPos.GetIndex()-1 ]->GetTxtNode();
991 aDestIdx.Assign( pDestTxtNd, pDestTxtNd->GetTxt().Len() );
993 // korrigiere den Bereich wieder !!
994 if( bEndEqualIns )
996 BOOL bChg = pEnd != rPam.GetPoint();
997 if( bChg )
998 rPam.Exchange();
999 rPam.Move( fnMoveBackward, fnGoCntnt );
1000 if( bChg )
1001 rPam.Exchange();
1003 aRg.aEnd = pEnd->nNode;
1004 pEndTxtNd = pEnd->nNode.GetNode().GetTxtNode();
1006 else if( rPos == *pEnd ) // Wurde das Ende auch verschoben
1008 pEnd->nNode--;
1009 pEnd->nContent.Assign( pDestTxtNd, nCntntEnd );
1010 aRg.aEnd = pEnd->nNode;
1011 pEndTxtNd = pEnd->nNode.GetNode().GetTxtNode();
1015 /* #107213#: Safe numrule item at destination. */
1016 // --> OD 2009-08-25 #i86492#
1017 // Safe also <ListId> item of destination.
1018 int aNumRuleState = SFX_ITEM_UNKNOWN;
1019 SwNumRuleItem aNumRuleItem;
1020 int aListIdState = SFX_ITEM_UNKNOWN;
1021 SfxStringItem aListIdItem( RES_PARATR_LIST_ID, String() );
1023 const SfxItemSet * pAttrSet = pDestTxtNd->GetpSwAttrSet();
1024 if (pAttrSet != NULL)
1026 const SfxPoolItem * pItem = NULL;
1027 aNumRuleState = pAttrSet->GetItemState(RES_PARATR_NUMRULE, FALSE, &pItem);
1028 if (SFX_ITEM_SET == aNumRuleState)
1029 aNumRuleItem = *((SwNumRuleItem *) pItem);
1031 aListIdState =
1032 pAttrSet->GetItemState(RES_PARATR_LIST_ID, FALSE, &pItem);
1033 if (SFX_ITEM_SET == aListIdState)
1035 aListIdItem.SetValue( static_cast<const SfxStringItem*>(pItem)->GetValue() );
1039 // <--
1040 /* #107213# */
1042 if( !bCopyOk )
1044 const xub_StrLen nCpyLen = ( (bOneNode)
1045 ? pEnd->nContent.GetIndex()
1046 : pSttTxtNd->GetTxt().Len() )
1047 - pStt->nContent.GetIndex();
1048 pSttTxtNd->CopyText( pDestTxtNd, aDestIdx,
1049 pStt->nContent, nCpyLen );
1050 if( bEndEqualIns )
1051 pEnd->nContent -= nCpyLen;
1054 if( bOneNode )
1056 if( bCopyCollFmt )
1058 pSttTxtNd->CopyCollFmt( *pDestTxtNd );
1060 /* #107213# If only a part of one paragraph is copied
1061 restore the numrule at the destination. */
1062 // --> OD 2009-08-25 #i86492#
1063 // restore also <ListId> item
1064 if ( !lcl_MarksWholeNode(rPam) )
1066 if (SFX_ITEM_SET == aNumRuleState)
1068 pDestTxtNd->SetAttr(aNumRuleItem);
1070 else
1072 pDestTxtNd->ResetAttr(RES_PARATR_NUMRULE);
1074 if (SFX_ITEM_SET == aListIdState)
1076 pDestTxtNd->SetAttr(aListIdItem);
1078 else
1080 pDestTxtNd->ResetAttr(RES_PARATR_LIST_ID);
1085 break;
1088 aRg.aStart++;
1091 else if( pDestTxtNd )
1093 // Problems with insertion of table selections into "normal" text solved.
1094 // We have to set the correct PaM for Undo, if this PaM starts in a textnode,
1095 // the undo operation will try to merge this node after removing the table.
1096 // If we didn't split a textnode, the PaM should start at the inserted table node
1097 if( rPos.nContent.GetIndex() == pDestTxtNd->Len() )
1098 { // Insertion at the last position of a textnode (empty or not)
1099 aInsPos++; // The table will be inserted behind the text node
1101 else if( rPos.nContent.GetIndex() )
1102 { // Insertion in the middle of a text node, it has to be split
1103 // (and joined from undo)
1104 bStartIsTxtNode = TRUE;
1105 // splitte den TextNode, bei dem Eingefuegt wird.
1107 xub_StrLen nCntntEnd = pEnd->nContent.GetIndex();
1108 BOOL bDoesUndo = pDoc->DoesUndo();
1109 pDoc->DoUndo( FALSE );
1110 pDoc->SplitNode( rPos, false );
1111 pDoc->DoUndo( bDoesUndo );
1113 if( bCanMoveBack && rPos == *aCpyPam.GetPoint() )
1115 // nach dem SplitNode, den CpyPam wieder richtig aufspannen
1116 aCpyPam.Move( fnMoveBackward, fnGoCntnt );
1117 aCpyPam.Move( fnMoveBackward, fnGoCntnt );
1120 // korrigiere den Bereich wieder !!
1121 if( bEndEqualIns )
1122 aRg.aEnd--;
1123 else if( rPos == *pEnd ) // Wurde das Ende auch verschoben
1125 rPos.nNode-=2;
1126 rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(),
1127 nCntntEnd );
1128 rPos.nNode++;
1129 aRg.aEnd--;
1132 else if( bCanMoveBack )
1133 { //Insertion at the first position of a text node. It will not be splitted, the table
1134 // will be inserted before the text node.
1135 // See below, before the SetInsertRange funciton of the undo object will be called,
1136 // the CpyPam would be moved to the next content position. This has to be avoided
1137 // We want to be moved to the table node itself thus we have to set bCanMoveBack
1138 // and to manipulate aCpyPam.
1139 bCanMoveBack = false;
1140 aCpyPam.GetPoint()->nNode--;
1144 pDestTxtNd = aInsPos.GetNode().GetTxtNode();
1145 if( pEndTxtNd )
1147 SwIndex aDestIdx( rPos.nContent );
1148 if( !pDestTxtNd )
1150 pDestTxtNd = pDoc->GetNodes().MakeTxtNode( aInsPos,
1151 pDoc->GetTxtCollFromPool(RES_POOLCOLL_STANDARD));
1152 aDestIdx.Assign( pDestTxtNd, 0 );
1153 aInsPos--;
1155 // #112756# #98130# if we have to insert an extra text node
1156 // at the destination, this node will be our new destination
1157 // (text) node, and thus we set bStartisTxtNode to true. This
1158 // will ensure that this node will be deleted during Undo
1159 // using JoinNext.
1160 DBG_ASSERT( !bStartIsTxtNode, "Oops, undo may be instable now." );
1161 bStartIsTxtNode = TRUE;
1164 /* #107213# Save numrule at destination */
1165 // --> OD 2009-08-25 #i86492#
1166 // Safe also <ListId> item of destination.
1167 int aNumRuleState = SFX_ITEM_UNKNOWN;
1168 SwNumRuleItem aNumRuleItem;
1169 int aListIdState = SFX_ITEM_UNKNOWN;
1170 SfxStringItem aListIdItem( RES_PARATR_LIST_ID, String() );
1172 const SfxItemSet* pAttrSet = pDestTxtNd->GetpSwAttrSet();
1173 if (pAttrSet != NULL)
1175 const SfxPoolItem * pItem = NULL;
1177 aNumRuleState =
1178 pAttrSet->GetItemState(RES_PARATR_NUMRULE, FALSE, &pItem);
1179 if (SFX_ITEM_SET == aNumRuleState)
1180 aNumRuleItem = *((SwNumRuleItem *) pItem);
1182 aListIdState =
1183 pAttrSet->GetItemState(RES_PARATR_LIST_ID, FALSE, &pItem);
1184 if (SFX_ITEM_SET == aListIdState)
1185 aListIdItem.SetValue( static_cast<const SfxStringItem*>(pItem)->GetValue() );
1188 // <--
1189 /* #107213# */
1191 const bool bEmptyDestNd = 0 == pDestTxtNd->GetTxt().Len();
1192 pEndTxtNd->CopyText( pDestTxtNd, aDestIdx, SwIndex( pEndTxtNd ),
1193 pEnd->nContent.GetIndex() );
1195 // auch alle FormatVorlagen kopieren
1196 if( bCopyCollFmt && ( bOneNode || bEmptyDestNd ))
1198 pEndTxtNd->CopyCollFmt( *pDestTxtNd );
1200 if ( bOneNode )
1202 /* #107213# If only a part of one paragraph is copied
1203 restore the numrule at the destination. */
1204 // --> OD 2009-08-25 #i86492#
1205 // restore also <ListId> item
1206 if ( !lcl_MarksWholeNode(rPam) )
1208 if (SFX_ITEM_SET == aNumRuleState)
1210 pDestTxtNd->SetAttr(aNumRuleItem);
1212 else
1214 pDestTxtNd->ResetAttr(RES_PARATR_NUMRULE);
1216 if (SFX_ITEM_SET == aListIdState)
1218 pDestTxtNd->SetAttr(aListIdItem);
1220 else
1222 pDestTxtNd->ResetAttr(RES_PARATR_LIST_ID);
1229 if( bCopyAll || aRg.aStart != aRg.aEnd )
1231 SfxItemSet aBrkSet( pDoc->GetAttrPool(), aBreakSetRange );
1232 if( pSttTxtNd && bCopyCollFmt && pDestTxtNd->HasSwAttrSet() )
1234 aBrkSet.Put( *pDestTxtNd->GetpSwAttrSet() );
1235 if( SFX_ITEM_SET == aBrkSet.GetItemState( RES_BREAK, FALSE ) )
1236 pDestTxtNd->ResetAttr( RES_BREAK );
1237 if( SFX_ITEM_SET == aBrkSet.GetItemState( RES_PAGEDESC, FALSE ) )
1238 pDestTxtNd->ResetAttr( RES_PAGEDESC );
1241 if( aInsPos == pEnd->nNode )
1243 SwNodeIndex aSaveIdx( aInsPos, -1 );
1244 CopyWithFlyInFly( aRg, 0,aInsPos, bMakeNewFrms, FALSE );
1245 aSaveIdx++;
1246 pEnd->nNode = aSaveIdx;
1247 pEnd->nContent.Assign( aSaveIdx.GetNode().GetTxtNode(), 0 );
1249 else
1250 CopyWithFlyInFly( aRg, pEnd->nContent.GetIndex(), aInsPos, bMakeNewFrms, FALSE );
1252 bCopyBookmarks = false;
1254 // harte Umbrueche wieder in den ersten Node setzen
1255 if( aBrkSet.Count() && 0 != ( pDestTxtNd = pDoc->GetNodes()[
1256 aCpyPam.GetPoint()->nNode.GetIndex()+1 ]->GetTxtNode() ) )
1258 pDestTxtNd->SetAttr( aBrkSet );
1261 } while( FALSE );
1263 // Position ummelden ( falls verschoben / im anderen Node )
1264 rPos.nContent.Assign( rPos.nNode.GetNode().GetCntntNode(),
1265 rPos.nContent.GetIndex() );
1267 if( rPos.nNode != aInsPos )
1269 aCpyPam.GetMark()->nNode = aInsPos;
1270 aCpyPam.GetMark()->nContent.Assign( aCpyPam.GetCntntNode(FALSE), 0 );
1271 rPos = *aCpyPam.GetMark();
1273 else
1274 *aCpyPam.GetMark() = rPos;
1276 aCpyPam.Move( fnMoveForward, bCanMoveBack ? fnGoCntnt : fnGoNode );
1277 aCpyPam.Exchange();
1279 // dann kopiere noch alle Bookmarks
1280 if( bCopyBookmarks && getIDocumentMarkAccess()->getMarksCount() )
1281 lcl_CopyBookmarks( rPam, aCpyPam );
1283 if( nsRedlineMode_t::REDLINE_DELETE_REDLINES & eOld )
1284 lcl_DeleteRedlines( rPam, aCpyPam );
1286 // falls Undo eingeschaltet ist, so speicher den eingefuegten Bereich
1287 if( pDoc->DoesUndo() )
1288 pUndo->SetInsertRange( aCpyPam, TRUE, bStartIsTxtNode );
1290 if( pCpyRange )
1292 pCpyRange->SetMark();
1293 *pCpyRange->GetPoint() = *aCpyPam.GetPoint();
1294 *pCpyRange->GetMark() = *aCpyPam.GetMark();
1297 if ( pNumRuleToPropagate )
1299 // --> OD 2009-08-25 #i86492#
1300 // use <SwDoc::SetNumRule(..)>, because it also handles the <ListId>
1301 // pDoc->ReplaceNumRule(aCpyPam, *pNumRuleToPropagate);
1302 pDoc->SetNumRule( aCpyPam, *pNumRuleToPropagate, false,
1303 aListIdToPropagate, sal_True, true );
1306 pDoc->SetRedlineMode_intern( eOld );
1307 pDoc->SetModified();
1309 return true;
1313 // ----- Copy-Methode vom SwDoc - "kopiere Fly's in Fly's" ------
1315 void SwDoc::CopyWithFlyInFly( const SwNodeRange& rRg, const xub_StrLen nEndContentIndex,
1316 const SwNodeIndex& rInsPos, BOOL bMakeNewFrms,
1317 BOOL bDelRedlines, BOOL bCopyFlyAtFly ) const
1319 SwDoc* pDest = rInsPos.GetNode().GetDoc();
1321 _SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 );
1323 SwNodeIndex aSavePos( rInsPos, -1 );
1324 BOOL bEndIsEqualEndPos = rInsPos == rRg.aEnd;
1325 GetNodes()._CopyNodes( rRg, rInsPos, bMakeNewFrms, TRUE );
1326 aSavePos++;
1327 if( bEndIsEqualEndPos )
1328 ((SwNodeIndex&)rRg.aEnd) = aSavePos;
1330 aRedlRest.Restore();
1332 #ifndef PRODUCT
1334 //JP 17.06.99: Bug 66973 - check count only if the selection is in
1335 // the same (or no) section. Becaus not full selected
1336 // section are not copied.
1337 const SwSectionNode* pSSectNd = rRg.aStart.GetNode().FindSectionNode();
1338 SwNodeIndex aTmpI( rRg.aEnd, -1 );
1339 const SwSectionNode* pESectNd = aTmpI.GetNode().FindSectionNode();
1340 if( pSSectNd == pESectNd &&
1341 !rRg.aStart.GetNode().IsSectionNode() &&
1342 !aTmpI.GetNode().IsEndNode() )
1344 ASSERT( rInsPos.GetIndex() - aSavePos.GetIndex() ==
1345 rRg.aEnd.GetIndex() - rRg.aStart.GetIndex(),
1346 "Es wurden zu wenig Nodes kopiert!" )
1349 #endif
1351 // Undo abschalten
1352 BOOL bUndo = pDest->DoesUndo();
1353 pDest->DoUndo( FALSE );
1354 CopyFlyInFlyImpl( rRg, nEndContentIndex, aSavePos, bCopyFlyAtFly );
1355 pDest->DoUndo( bUndo );
1357 SwNodeRange aCpyRange( aSavePos, rInsPos );
1359 // dann kopiere noch alle Bookmarks
1360 if( getIDocumentMarkAccess()->getMarksCount() )
1362 SwPaM aRgTmp( rRg.aStart, rRg.aEnd );
1363 SwPaM aCpyTmp( aCpyRange.aStart, aCpyRange.aEnd );
1365 lcl_CopyBookmarks( aRgTmp, aCpyTmp );
1368 if( bDelRedlines && ( nsRedlineMode_t::REDLINE_DELETE_REDLINES & pDest->GetRedlineMode() ))
1369 lcl_DeleteRedlines( rRg, aCpyRange );
1371 pDest->GetNodes()._DelDummyNodes( aCpyRange );
1374 void lcl_ChainFmts( SwFlyFrmFmt *pSrc, SwFlyFrmFmt *pDest )
1376 SwFmtChain aSrc( pSrc->GetChain() );
1377 if ( !aSrc.GetNext() )
1379 aSrc.SetNext( pDest );
1380 pSrc->SetFmtAttr( aSrc );
1382 SwFmtChain aDest( pDest->GetChain() );
1383 if ( !aDest.GetPrev() )
1385 aDest.SetPrev( pSrc );
1386 pDest->SetFmtAttr( aDest );
1390 void SwDoc::CopyFlyInFlyImpl( const SwNodeRange& rRg,
1391 const xub_StrLen nEndContentIndex, const SwNodeIndex& rStartIdx,
1392 const bool bCopyFlyAtFly ) const
1394 // Bug 22727: suche erst mal alle Flys zusammen, sortiere sie entsprechend
1395 // ihrer Ordnungsnummer und kopiere sie erst dann. Damit wird
1396 // die Ordnungsnummer (wird nur im DrawModel verwaltet)
1397 // beibehalten.
1398 SwDoc *const pDest = rStartIdx.GetNode().GetDoc();
1399 _ZSortFlys aArr;
1400 USHORT nArrLen = GetSpzFrmFmts()->Count();
1401 USHORT n;
1403 for( n = 0; n < nArrLen; ++n )
1405 const SwFrmFmt* pFmt = (*GetSpzFrmFmts())[n];
1406 const SwFmtAnchor* pAnchor = &pFmt->GetAnchor();
1407 const SwPosition* pAPos;
1408 bool bAtCntnt = pAnchor->GetAnchorId() == FLY_AT_CNTNT;
1409 if ( ( bAtCntnt ||
1410 pAnchor->GetAnchorId() == FLY_AT_FLY ||
1411 pAnchor->GetAnchorId() == FLY_AUTO_CNTNT ) &&
1412 0 != ( pAPos = pAnchor->GetCntntAnchor()) &&
1413 (( bCopyFlyAtFly && FLY_AT_FLY == pAnchor->GetAnchorId() )
1414 ? rRg.aStart <= pAPos->nNode.GetIndex() + 1
1415 : ( IsRedlineMove()
1416 ? rRg.aStart < pAPos->nNode
1417 : rRg.aStart <= pAPos->nNode )) &&
1418 pAPos->nNode <= rRg.aEnd )
1420 //frames at the last source node are not always copied:
1421 //- if the node is empty and is the last node of the document or a table cell
1422 // or a text frame then tey have to be copied
1423 //- if the content index in this node is > 0 then paragph and frame bound objects are copied
1424 //- to-character bound objects are copied if their index is <= nEndContentIndex
1425 bool bAdd = false;
1426 if( pAPos->nNode < rRg.aEnd )
1427 bAdd = true;
1428 if( !bAdd )
1430 bool bEmptyNode = false;
1431 bool bLastNode = false;
1432 // is the node empty?
1433 const SwNodes& rNodes = pAPos->nNode.GetNodes();
1434 SwTxtNode* pTxtNode;
1435 if( 0 != ( pTxtNode = pAPos->nNode.GetNode().GetTxtNode() ))
1437 bEmptyNode = !pTxtNode->GetTxt().Len();
1438 if( bEmptyNode )
1440 //last node information is only necessary to know for the last TextNode
1441 SwNodeIndex aTmp( pAPos->nNode );
1442 ++aTmp;//goto next node
1443 while( rNodes[aTmp ]->IsEndNode() )
1445 if( aTmp == rNodes.GetEndOfContent().GetIndex() )
1447 bLastNode = true;
1448 break;
1450 ++aTmp;
1454 bAdd = bLastNode && bEmptyNode;
1455 if( !bAdd )
1457 if( bAtCntnt )
1458 bAdd = nEndContentIndex > 0;
1459 else
1460 bAdd = pAPos->nContent <= nEndContentIndex;
1463 if( bAdd )
1464 aArr.Insert( _ZSortFly( pFmt, pAnchor, nArrLen + aArr.Count() ));
1468 //Alle kopierten (also die neu erzeugten) Rahmen in ein weiteres Array
1469 //stopfen. Dort sizten sie passend zu den Originalen, damit hinterher
1470 //die Chains entsprechend aufgebaut werden koennen.
1471 SvPtrarr aNewArr( 10, 10 );
1473 for( n = 0; n < aArr.Count(); ++n )
1475 const _ZSortFly& rZSortFly = aArr[ n ];
1477 // --> OD 2006-01-04 #i59964#
1478 // correct determination of new anchor position
1479 SwFmtAnchor aAnchor( *rZSortFly.GetAnchor() );
1480 SwPosition* pNewPos = (SwPosition*)aAnchor.GetCntntAnchor();
1481 // for at-paragraph and at-character anchored objects the new anchor
1482 // position can *not* be determined by the difference of the current
1483 // anchor position to the start of the copied range, because not
1484 // complete selected sections in the copied range aren't copied - see
1485 // method <SwNodes::_CopyNodes(..)>.
1486 // Thus, the new anchor position in the destination document is found
1487 // by counting the text nodes.
1488 if ( aAnchor.GetAnchorId() == FLY_AT_CNTNT ||
1489 aAnchor.GetAnchorId() == FLY_AUTO_CNTNT )
1491 // First, determine number of anchor text node in the copied range.
1492 // Note: The anchor text node *have* to be inside the copied range.
1493 ULONG nAnchorTxtNdNumInRange( 0L );
1494 bool bAnchorTxtNdFound( false );
1495 SwNodeIndex aIdx( rRg.aStart );
1496 while ( !bAnchorTxtNdFound && aIdx <= rRg.aEnd )
1498 if ( aIdx.GetNode().IsTxtNode() )
1500 ++nAnchorTxtNdNumInRange;
1501 bAnchorTxtNdFound = aAnchor.GetCntntAnchor()->nNode == aIdx;
1504 ++aIdx;
1506 if ( !bAnchorTxtNdFound )
1508 // This case can *not* happen, but to be robust take the first
1509 // text node in the destination document.
1510 ASSERT( false,
1511 "<SwDoc::_CopyFlyInFly(..)> - anchor text node in copied range not found" );
1512 nAnchorTxtNdNumInRange = 1;
1514 // Second, search corresponding text node in destination document
1515 // by counting forward from start insert position <rStartIdx> the
1516 // determined number of text nodes.
1517 aIdx = rStartIdx;
1518 SwNodeIndex aAnchorNdIdx( rStartIdx );
1519 const SwNode& aEndOfContentNd =
1520 aIdx.GetNode().GetNodes().GetEndOfContent();
1521 while ( nAnchorTxtNdNumInRange > 0 &&
1522 &(aIdx.GetNode()) != &aEndOfContentNd )
1524 if ( aIdx.GetNode().IsTxtNode() )
1526 --nAnchorTxtNdNumInRange;
1527 aAnchorNdIdx = aIdx;
1530 ++aIdx;
1532 if ( !aAnchorNdIdx.GetNode().IsTxtNode() )
1534 // This case can *not* happen, but to be robust take the first
1535 // text node in the destination document.
1536 ASSERT( false,
1537 "<SwDoc::_CopyFlyInFly(..)> - found anchor node index isn't a text node" );
1538 aAnchorNdIdx = rStartIdx;
1539 while ( !aAnchorNdIdx.GetNode().IsTxtNode() )
1541 ++aAnchorNdIdx;
1544 // apply found anchor text node as new anchor position
1545 pNewPos->nNode = aAnchorNdIdx;
1547 else
1549 long nOffset = pNewPos->nNode.GetIndex() - rRg.aStart.GetIndex();
1550 SwNodeIndex aIdx( rStartIdx, nOffset );
1551 pNewPos->nNode = aIdx;
1553 // <--
1554 // die am Zeichen Flys wieder ans das vorgegebene Zeichen setzen
1555 if ( FLY_AUTO_CNTNT == aAnchor.GetAnchorId() &&
1556 pNewPos->nNode.GetNode().IsTxtNode() )
1558 pNewPos->nContent.Assign( (SwTxtNode*)&pNewPos->nNode.GetNode(),
1559 pNewPos->nContent.GetIndex() );
1561 else
1563 pNewPos->nContent.Assign( 0, 0 );
1566 // ueberpruefe Rekursion: Inhalt in "seinen eigenen" Frame
1567 // kopieren. Dann nicht kopieren
1568 BOOL bMakeCpy = TRUE;
1569 if( pDest == this )
1571 const SwFmtCntnt& rCntnt = rZSortFly.GetFmt()->GetCntnt();
1572 const SwStartNode* pSNd;
1573 if( rCntnt.GetCntntIdx() &&
1574 0 != ( pSNd = rCntnt.GetCntntIdx()->GetNode().GetStartNode() ) &&
1575 pSNd->GetIndex() < rStartIdx.GetIndex() &&
1576 rStartIdx.GetIndex() < pSNd->EndOfSectionIndex() )
1578 bMakeCpy = FALSE;
1579 aArr.Remove( n, 1 );
1580 --n;
1584 // Format kopieren und den neuen Anker setzen
1585 if( bMakeCpy )
1586 aNewArr.Insert( pDest->CopyLayoutFmt( *rZSortFly.GetFmt(),
1587 aAnchor, false, true ), aNewArr.Count() );
1590 //Alle chains, die im Original vorhanden sind, soweit wie moeglich wieder
1591 //aufbauen.
1592 ASSERT( aArr.Count() == aNewArr.Count(), "Missing new Flys" );
1593 if ( aArr.Count() == aNewArr.Count() )
1595 for ( n = 0; n < aArr.Count(); ++n )
1597 const SwFrmFmt *pFmt = aArr[n].GetFmt();
1598 const SwFmtChain &rChain = pFmt->GetChain();
1599 int nCnt = 0 != rChain.GetPrev();
1600 nCnt += rChain.GetNext() ? 1: 0;
1601 for ( USHORT k = 0; nCnt && k < aArr.Count(); ++k )
1603 const _ZSortFly &rTmp = aArr[k];
1604 const SwFrmFmt *pTmp = rTmp.GetFmt();
1605 if ( rChain.GetPrev() == pTmp )
1607 ::lcl_ChainFmts( (SwFlyFrmFmt*)aNewArr[k],
1608 (SwFlyFrmFmt*)aNewArr[n] );
1609 --nCnt;
1611 else if ( rChain.GetNext() == pTmp )
1613 ::lcl_ChainFmts( (SwFlyFrmFmt*)aNewArr[n],
1614 (SwFlyFrmFmt*)aNewArr[k] );
1615 --nCnt;