merge the formfield patch from ooo-build
[ooovba.git] / sw / source / core / doc / tblcpy.cxx
blob6bca094d3e56e696728ada741950ad36a6462971
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tblcpy.cxx,v $
10 * $Revision: 1.12 $
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 #include <hintids.hxx>
37 #define _ZFORLIST_DECLARE_TABLE
38 #include <svtools/zforlist.hxx>
39 #include <frmfmt.hxx>
40 #include <doc.hxx>
41 #include <cntfrm.hxx>
42 #include <pam.hxx>
43 #include <swtable.hxx>
44 #include <ndtxt.hxx>
45 #include <fldbas.hxx>
46 #include <tblsel.hxx>
47 #include <tabfrm.hxx>
48 #include <poolfmt.hxx>
49 #include <cellatr.hxx>
50 #include <mvsave.hxx>
51 #include <docary.hxx>
52 #include <fmtanchr.hxx>
53 #include <undobj.hxx>
54 #include <redline.hxx>
55 #include <fmtfsize.hxx>
56 #include <list>
58 BOOL _FndCntntLine( const SwTableLine*& rpLine, void* pPara );
59 BOOL _FndCntntBox( const SwTableBox*& rpBox, void* pPara );
60 void lcl_CpyBox( const SwTable& rCpyTbl, const SwTableBox* pCpyBox,
61 SwTable& rDstTbl, SwTableBox* pDstBox,
62 BOOL bDelCntnt, SwUndoTblCpyTbl* pUndo );
64 // The following type will be used by table copy functions to describe
65 // the structure of tables (or parts of tables).
66 // It's for new table model only.
68 namespace
70 struct BoxSpanInfo
72 SwTableBox* mpBox;
73 SwTableBox* mpCopy;
74 USHORT mnColSpan;
75 bool mbSelected;
78 typedef std::vector< BoxSpanInfo > BoxStructure;
79 typedef std::vector< BoxStructure > LineStructure;
80 typedef std::list< ULONG > ColumnStructure;
82 struct SubBox
84 SwTableBox *mpBox;
85 bool mbCovered;
88 typedef std::list< SubBox > SubLine;
89 typedef std::list< SubLine > SubTable;
91 class TableStructure
93 public:
94 LineStructure maLines;
95 ColumnStructure maCols;
96 USHORT mnStartCol;
97 USHORT mnAddLine;
98 void addLine( USHORT &rLine, const SwTableBoxes&, const SwSelBoxes*,
99 bool bNewModel );
100 void addBox( USHORT nLine, const SwSelBoxes*, SwTableBox *pBox,
101 ULONG &rnB, USHORT &rnC, ColumnStructure::iterator& rpCl,
102 BoxStructure::iterator& rpSel, bool &rbSel, bool bCover );
103 void incColSpan( USHORT nLine, USHORT nCol );
104 TableStructure( const SwTable& rTable );
105 TableStructure( const SwTable& rTable, _FndBox &rFndBox,
106 const SwSelBoxes& rSelBoxes,
107 LineStructure::size_type nMinSize );
108 LineStructure::size_type getLineCount() const
109 { return maLines.size(); }
110 void moreLines( const SwTable& rTable );
111 void assignBoxes( const TableStructure &rSource );
112 void copyBoxes( const SwTable& rSource, SwTable& rDstTbl,
113 SwUndoTblCpyTbl* pUndo ) const;
116 SubTable::iterator insertSubLine( SubTable& rSubTable, SwTableLine& rLine,
117 SubTable::iterator pStartLn );
119 SubTable::iterator insertSubBox( SubTable& rSubTable, SwTableBox& rBox,
120 SubTable::iterator pStartLn, SubTable::iterator pEndLn )
122 if( rBox.GetTabLines().Count() )
124 SubTable::difference_type nSize = std::distance( pStartLn, pEndLn );
125 if( nSize < rBox.GetTabLines().Count() )
127 SubLine aSubLine;
128 SubLine::iterator pBox = pStartLn->begin();
129 SubLine::iterator pEnd = pStartLn->end();
130 while( pBox != pEnd )
132 SubBox aSub;
133 aSub.mpBox = pBox->mpBox;
134 aSub.mbCovered = true;
135 aSubLine.push_back( aSub );
136 ++pBox;
140 rSubTable.insert( pEndLn, aSubLine );
141 } while( ++nSize < rBox.GetTabLines().Count() );
143 for( USHORT nLine = 0; nLine < rBox.GetTabLines().Count(); ++nLine )
144 pStartLn = insertSubLine( rSubTable, *rBox.GetTabLines()[nLine],
145 pStartLn );
146 ASSERT( pStartLn == pEndLn, "Sub line confusion" );
148 else
150 SubBox aSub;
151 aSub.mpBox = &rBox;
152 aSub.mbCovered = false;
153 while( pStartLn != pEndLn )
155 pStartLn->push_back( aSub );
156 aSub.mbCovered = true;
157 ++pStartLn;
160 return pStartLn;
163 SubTable::iterator insertSubLine( SubTable& rSubTable, SwTableLine& rLine,
164 SubTable::iterator pStartLn )
166 SubTable::iterator pMax = pStartLn;
167 ++pMax;
168 SubTable::difference_type nMax = 1;
169 for( USHORT nBox = 0; nBox < rLine.GetTabBoxes().Count(); ++nBox )
171 SubTable::iterator pTmp = insertSubBox( rSubTable,
172 *rLine.GetTabBoxes()[nBox], pStartLn, pMax );
173 SubTable::difference_type nTmp = std::distance( pStartLn, pTmp );
174 if( nTmp > nMax )
176 pMax = pTmp;
177 nMax = nTmp;
180 return pMax;
183 TableStructure::TableStructure( const SwTable& rTable ) :
184 maLines( rTable.GetTabLines().Count() ), mnStartCol(USHRT_MAX),
185 mnAddLine(0)
187 maCols.push_front(0);
188 const SwTableLines &rLines = rTable.GetTabLines();
189 USHORT nCnt = 0;
190 for( USHORT nLine = 0; nLine < rLines.Count(); ++nLine )
191 addLine( nCnt, rLines[nLine]->GetTabBoxes(), 0, rTable.IsNewModel() );
194 TableStructure::TableStructure( const SwTable& rTable,
195 _FndBox &rFndBox, const SwSelBoxes& rSelBoxes,
196 LineStructure::size_type nMinSize )
197 : mnStartCol(USHRT_MAX), mnAddLine(0)
199 if( rFndBox.GetLines().Count() )
201 bool bNoSelection = rSelBoxes.Count() < 2;
202 _FndLines &rFndLines = rFndBox.GetLines();
203 maCols.push_front(0);
204 const SwTableLine* pLine = rFndLines[0]->GetLine();
205 USHORT nStartLn = rTable.GetTabLines().C40_GETPOS( SwTableLine, pLine );
206 USHORT nEndLn = nStartLn;
207 if( rFndLines.Count() > 1 )
209 pLine = rFndLines[ rFndLines.Count()-1 ]->GetLine();
210 nEndLn = rTable.GetTabLines().C40_GETPOS( SwTableLine, pLine );
212 if( nStartLn < USHRT_MAX && nEndLn < USHRT_MAX )
214 const SwTableLines &rLines = rTable.GetTabLines();
215 if( bNoSelection &&
216 (USHORT)nMinSize > nEndLn - nStartLn + 1 )
218 USHORT nNewEndLn = nStartLn + (USHORT)nMinSize - 1;
219 if( nNewEndLn >= rLines.Count() )
221 mnAddLine = nNewEndLn - rLines.Count() + 1;
222 nNewEndLn = rLines.Count() - 1;
224 while( nEndLn < nNewEndLn )
226 SwTableLine *pLine2 = rLines[ ++nEndLn ];
227 SwTableBox *pTmpBox = pLine2->GetTabBoxes()[0];
228 _FndLine *pInsLine = new _FndLine( pLine2, &rFndBox );
229 _FndBox *pFndBox = new _FndBox( pTmpBox, pInsLine );
230 pInsLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, 0 );
231 rFndLines.C40_INSERT( _FndLine, pInsLine, rFndLines.Count() );
234 maLines.resize( nEndLn - nStartLn + 1 );
235 const SwSelBoxes* pSelBoxes = &rSelBoxes;
236 USHORT nCnt = 0;
237 for( USHORT nLine = nStartLn; nLine <= nEndLn; ++nLine )
239 addLine( nCnt, rLines[nLine]->GetTabBoxes(),
240 pSelBoxes, rTable.IsNewModel() );
241 if( bNoSelection )
242 pSelBoxes = 0;
245 if( bNoSelection && mnStartCol < USHRT_MAX )
247 BoxStructure::iterator pC = maLines[0].begin();
248 BoxStructure::iterator pEnd = maLines[0].end();
249 USHORT nIdx = mnStartCol;
250 mnStartCol = 0;
251 while( nIdx && pC != pEnd )
253 mnStartCol = mnStartCol + pC->mnColSpan;
254 --nIdx;
255 ++pC;
258 else
259 mnStartCol = USHRT_MAX;
263 void TableStructure::addLine( USHORT &rLine, const SwTableBoxes& rBoxes,
264 const SwSelBoxes* pSelBoxes, bool bNewModel )
266 bool bComplex = false;
267 if( !bNewModel )
268 for( USHORT nBox = 0; !bComplex && nBox < rBoxes.Count(); ++nBox )
269 bComplex = rBoxes[nBox]->GetTabLines().Count() > 0;
270 if( bComplex )
272 SubTable aSubTable;
273 SubLine aSubLine;
274 aSubTable.push_back( aSubLine );
275 SubTable::iterator pStartLn = aSubTable.begin();
276 SubTable::iterator pEndLn = aSubTable.end();
277 for( USHORT nBox = 0; nBox < rBoxes.Count(); ++nBox )
278 insertSubBox( aSubTable, *rBoxes[nBox], pStartLn, pEndLn );
279 SubTable::size_type nSize = aSubTable.size();
280 if( nSize )
282 maLines.resize( maLines.size() + nSize - 1 );
283 while( pStartLn != pEndLn )
285 bool bSelected = false;
286 ULONG nBorder = 0;
287 USHORT nCol = 0;
288 maLines[rLine].reserve( pStartLn->size() );
289 BoxStructure::iterator pSel = maLines[rLine].end();
290 ColumnStructure::iterator pCol = maCols.begin();
291 SubLine::iterator pBox = pStartLn->begin();
292 SubLine::iterator pEnd = pStartLn->end();
293 while( pBox != pEnd )
295 addBox( rLine, pSelBoxes, pBox->mpBox, nBorder, nCol,
296 pCol, pSel, bSelected, pBox->mbCovered );
297 ++pBox;
299 ++rLine;
300 ++pStartLn;
304 else
306 bool bSelected = false;
307 ULONG nBorder = 0;
308 USHORT nCol = 0;
309 maLines[rLine].reserve( rBoxes.Count() );
310 ColumnStructure::iterator pCol = maCols.begin();
311 BoxStructure::iterator pSel = maLines[rLine].end();
312 for( USHORT nBox = 0; nBox < rBoxes.Count(); ++nBox )
313 addBox( rLine, pSelBoxes, rBoxes[nBox], nBorder, nCol,
314 pCol, pSel, bSelected, false );
315 ++rLine;
319 void TableStructure::addBox( USHORT nLine, const SwSelBoxes* pSelBoxes,
320 SwTableBox *pBox, ULONG &rnBorder, USHORT &rnCol,
321 ColumnStructure::iterator& rpCol, BoxStructure::iterator& rpSel,
322 bool &rbSelected, bool bCovered )
324 BoxSpanInfo aInfo;
325 if( pSelBoxes &&
326 USHRT_MAX != pSelBoxes->GetPos( pBox ) )
328 aInfo.mbSelected = true;
329 if( mnStartCol == USHRT_MAX )
331 mnStartCol = (USHORT)maLines[nLine].size();
332 if( pSelBoxes->Count() < 2 )
334 pSelBoxes = 0;
335 aInfo.mbSelected = false;
339 else
340 aInfo.mbSelected = false;
341 rnBorder += pBox->GetFrmFmt()->GetFrmSize().GetWidth();
342 USHORT nLeftCol = rnCol;
343 while( rpCol != maCols.end() && *rpCol < rnBorder )
345 ++rnCol;
346 ++rpCol;
348 if( rpCol == maCols.end() || *rpCol > rnBorder )
350 maCols.insert( rpCol, rnBorder );
351 --rpCol;
352 incColSpan( nLine, rnCol );
354 aInfo.mnColSpan = rnCol - nLeftCol;
355 aInfo.mpCopy = 0;
356 aInfo.mpBox = bCovered ? 0 : pBox;
357 maLines[nLine].push_back( aInfo );
358 if( aInfo.mbSelected )
360 if( rbSelected )
362 while( rpSel != maLines[nLine].end() )
364 rpSel->mbSelected = true;
365 ++rpSel;
368 else
370 rpSel = maLines[nLine].end();
371 rbSelected = true;
373 --rpSel;
377 void TableStructure::moreLines( const SwTable& rTable )
379 if( mnAddLine )
381 const SwTableLines &rLines = rTable.GetTabLines();
382 USHORT nLineCount = rLines.Count();
383 if( nLineCount < mnAddLine )
384 mnAddLine = nLineCount;
385 USHORT nLine = (USHORT)maLines.size();
386 maLines.resize( nLine + mnAddLine );
387 while( mnAddLine )
389 SwTableLine *pLine = rLines[ nLineCount - mnAddLine ];
390 addLine( nLine, pLine->GetTabBoxes(), 0, rTable.IsNewModel() );
391 --mnAddLine;
396 void TableStructure::incColSpan( USHORT nLineMax, USHORT nNewCol )
398 for( USHORT nLine = 0; nLine < nLineMax; ++nLine )
400 BoxStructure::iterator pInfo = maLines[nLine].begin();
401 BoxStructure::iterator pEnd = maLines[nLine].end();
402 long nCol = pInfo->mnColSpan;
403 while( nNewCol > nCol && ++pInfo != pEnd )
404 nCol += pInfo->mnColSpan;
405 if( pInfo != pEnd )
406 ++(pInfo->mnColSpan);
410 void TableStructure::assignBoxes( const TableStructure &rSource )
412 LineStructure::const_iterator pFirstLine = rSource.maLines.begin();
413 LineStructure::const_iterator pLastLine = rSource.maLines.end();
414 if( pFirstLine == pLastLine )
415 return;
416 LineStructure::const_iterator pCurrLine = pFirstLine;
417 LineStructure::size_type nLineCount = maLines.size();
418 USHORT nFirstStartCol = 0;
420 BoxStructure::const_iterator pFirstBox = pFirstLine->begin();
421 if( pFirstBox != pFirstLine->end() && pFirstBox->mpBox &&
422 pFirstBox->mpBox->getDummyFlag() )
423 nFirstStartCol = pFirstBox->mnColSpan;
425 for( LineStructure::size_type nLine = 0; nLine < nLineCount; ++nLine )
427 BoxStructure::const_iterator pFirstBox = pCurrLine->begin();
428 BoxStructure::const_iterator pLastBox = pCurrLine->end();
429 USHORT nCurrStartCol = mnStartCol;
430 if( pFirstBox != pLastBox )
432 BoxStructure::const_iterator pTmpBox = pLastBox;
433 --pTmpBox;
434 if( pTmpBox->mpBox && pTmpBox->mpBox->getDummyFlag() )
435 --pLastBox;
436 if( pFirstBox != pLastBox && pFirstBox->mpBox &&
437 pFirstBox->mpBox->getDummyFlag() )
439 if( nCurrStartCol < USHRT_MAX )
441 if( pFirstBox->mnColSpan > nFirstStartCol )
442 nCurrStartCol = pFirstBox->mnColSpan - nFirstStartCol
443 + nCurrStartCol;
445 ++pFirstBox;
448 if( pFirstBox != pLastBox )
450 BoxStructure::const_iterator pCurrBox = pFirstBox;
451 BoxStructure &rBox = maLines[nLine];
452 BoxStructure::size_type nBoxCount = rBox.size();
453 USHORT nCol = 0;
454 for( BoxStructure::size_type nBox = 0; nBox < nBoxCount; ++nBox )
456 BoxSpanInfo& rInfo = rBox[nBox];
457 nCol = nCol + rInfo.mnColSpan;
458 if( rInfo.mbSelected || nCol > nCurrStartCol )
460 rInfo.mpCopy = pCurrBox->mpBox;
461 if( rInfo.mbSelected && rInfo.mpCopy->getDummyFlag() )
463 ++pCurrBox;
464 if( pCurrBox == pLastBox )
466 pCurrBox = pFirstBox;
467 if( pCurrBox->mpBox->getDummyFlag() )
468 ++pCurrBox;
470 rInfo.mpCopy = pCurrBox->mpBox;
472 ++pCurrBox;
473 if( pCurrBox == pLastBox )
475 if( rInfo.mbSelected )
476 pCurrBox = pFirstBox;
477 else
479 rInfo.mbSelected = rInfo.mpCopy == 0;
480 break;
483 rInfo.mbSelected = rInfo.mpCopy == 0;
487 ++pCurrLine;
488 if( pCurrLine == pLastLine )
489 pCurrLine = pFirstLine;
493 void TableStructure::copyBoxes( const SwTable& rSource, SwTable& rDstTbl,
494 SwUndoTblCpyTbl* pUndo ) const
496 LineStructure::size_type nLineCount = maLines.size();
497 for( LineStructure::size_type nLine = 0; nLine < nLineCount; ++nLine )
499 const BoxStructure &rBox = maLines[nLine];
500 BoxStructure::size_type nBoxCount = rBox.size();
501 for( BoxStructure::size_type nBox = 0; nBox < nBoxCount; ++nBox )
503 const BoxSpanInfo& rInfo = rBox[nBox];
504 if( ( rInfo.mpCopy && !rInfo.mpCopy->getDummyFlag() )
505 || rInfo.mbSelected )
507 SwTableBox *pBox = rInfo.mpBox;
508 if( pBox && pBox->getRowSpan() > 0 )
509 lcl_CpyBox( rSource, rInfo.mpCopy, rDstTbl, pBox,
510 TRUE, pUndo );
511 /* Idea: If target cell is a covered cell, append content
512 to master cell.
513 BOOL bReplace = TRUE;
514 if( pBox->getRowSpan() < 0 )
516 if( rInfo.mpCopy->getRowSpan() < 0 )
517 continue;
518 pBox = &pBox->FindStartOfRowSpan( rDstTbl );
519 bReplace = FALSE;
521 lcl_CpyBox( rSource, rInfo.mpCopy, rDstTbl, pBox,
522 bReplace, pUndo );
530 // ---------------------------------------------------------------
532 // kopiere die Tabelle in diese.
533 // Kopiere alle Boxen einer Line in entsprechenden Boxen. Der alte Inhalt
534 // wird dabei geloescht.
535 // Ist keine mehr vorhanden, kommt der restliche Inhalt in die letzte
536 // Box einer "GrundLine".
537 // Ist auch keine Line mehr vorhanden, -> auch in die letzte Box
538 // einer "GrundLine"
541 void lcl_CpyBox( const SwTable& rCpyTbl, const SwTableBox* pCpyBox,
542 SwTable& rDstTbl, SwTableBox* pDstBox,
543 BOOL bDelCntnt, SwUndoTblCpyTbl* pUndo )
545 ASSERT( ( !pCpyBox || pCpyBox->GetSttNd() ) && pDstBox->GetSttNd(),
546 "Keine inhaltstragende Box" );
548 SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc();
549 SwDoc* pDoc = rDstTbl.GetFrmFmt()->GetDoc();
551 // kopiere erst den neuen und loeschen dann den alten Inhalt
552 // (keine leeren Section erzeugen; werden sonst geloescht!)
553 std::auto_ptr< SwNodeRange > pRg( pCpyBox ?
554 new SwNodeRange ( *pCpyBox->GetSttNd(), 1,
555 *pCpyBox->GetSttNd()->EndOfSectionNode() ) : 0 );
557 SwNodeIndex aInsIdx( *pDstBox->GetSttNd(), bDelCntnt ? 1 :
558 pDstBox->GetSttNd()->EndOfSectionIndex() -
559 pDstBox->GetSttIdx() );
561 if( pUndo )
562 pUndo->AddBoxBefore( *pDstBox, bDelCntnt );
564 BOOL bUndo = pDoc->DoesUndo();
565 bool bUndoRedline = pUndo && pDoc->IsRedlineOn();
566 pDoc->DoUndo( FALSE );
568 SwNodeIndex aSavePos( aInsIdx, -1 );
569 if( pRg.get() )
570 pCpyDoc->CopyWithFlyInFly( *pRg, 0, aInsIdx, FALSE );
571 else
572 pDoc->GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() );
573 aSavePos++;
575 SwTableLine* pLine = pDstBox->GetUpper();
576 while( pLine->GetUpper() )
577 pLine = pLine->GetUpper()->GetUpper();
579 BOOL bReplaceColl = TRUE;
580 if( bDelCntnt && !bUndoRedline )
582 // zuerst die Fly loeschen, dann die entsprechenden Nodes
583 SwNodeIndex aEndNdIdx( *aInsIdx.GetNode().EndOfSectionNode() );
585 // Bookmarks usw. verschieben
587 SwPosition aMvPos( aInsIdx );
588 SwCntntNode* pCNd = pDoc->GetNodes().GoPrevious( &aMvPos.nNode );
589 aMvPos.nContent.Assign( pCNd, pCNd->Len() );
590 pDoc->CorrAbs( aInsIdx, aEndNdIdx, aMvPos, /*TRUE*/FALSE );
593 // stehen noch FlyFrames rum, loesche auch diese
594 const SwPosition* pAPos;
595 for( USHORT n = 0; n < pDoc->GetSpzFrmFmts()->Count(); ++n )
597 SwFrmFmt* pFly = (*pDoc->GetSpzFrmFmts())[n];
598 const SwFmtAnchor* pAnchor = &pFly->GetAnchor();
599 if( ( FLY_AT_CNTNT == pAnchor->GetAnchorId() ||
600 FLY_AUTO_CNTNT == pAnchor->GetAnchorId() ) &&
601 0 != ( pAPos = pAnchor->GetCntntAnchor() ) &&
602 aInsIdx <= pAPos->nNode && pAPos->nNode <= aEndNdIdx )
604 pDoc->DelLayoutFmt( pFly );
608 // ist DestBox eine Headline-Box und hat Tabellen-Vorlage gesetzt,
609 // dann NICHT die TabellenHeadline-Vorlage automatisch setzen
610 if( 1 < rDstTbl.GetTabLines().Count() &&
611 pLine == rDstTbl.GetTabLines()[0] )
613 SwCntntNode* pCNd = aInsIdx.GetNode().GetCntntNode();
614 if( !pCNd )
616 SwNodeIndex aTmp( aInsIdx );
617 pCNd = pDoc->GetNodes().GoNext( &aTmp );
620 if( pCNd &&
621 /*RES_POOLCOLL_TABLE == */
622 RES_POOLCOLL_TABLE_HDLN !=
623 pCNd->GetFmtColl()->GetPoolFmtId() )
624 bReplaceColl = FALSE;
627 pDoc->GetNodes().Delete( aInsIdx, aEndNdIdx.GetIndex() - aInsIdx.GetIndex() );
630 //b6341295: Table copy redlining will be managed by AddBoxAfter()
631 if( pUndo )
632 pUndo->AddBoxAfter( *pDstBox, aInsIdx, bDelCntnt );
634 // Ueberschrift
635 SwTxtNode* pTxtNd = pDoc->GetNodes()[ aSavePos ]->GetTxtNode();
636 if( pTxtNd )
638 USHORT nPoolId = pTxtNd->GetTxtColl()->GetPoolFmtId();
639 if( bReplaceColl &&
640 (( 1 < rDstTbl.GetTabLines().Count() &&
641 pLine == rDstTbl.GetTabLines()[0] )
642 // gilt noch die Tabellen-Inhalt ??
643 ? RES_POOLCOLL_TABLE == nPoolId
644 : RES_POOLCOLL_TABLE_HDLN == nPoolId ) )
646 SwTxtFmtColl* pColl = pDoc->GetTxtCollFromPool(
647 static_cast<sal_uInt16>(
648 RES_POOLCOLL_TABLE == nPoolId
649 ? RES_POOLCOLL_TABLE_HDLN
650 : RES_POOLCOLL_TABLE ) );
651 if( pColl ) // Vorlage umsetzen
653 SwPaM aPam( aSavePos );
654 aPam.SetMark();
655 aPam.Move( fnMoveForward, fnGoSection );
656 pDoc->SetTxtFmtColl( aPam, pColl );
660 // loesche die akt. Formel/Format/Value Werte
661 if( SFX_ITEM_SET == pDstBox->GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT ) ||
662 SFX_ITEM_SET == pDstBox->GetFrmFmt()->GetItemState( RES_BOXATR_FORMULA ) ||
663 SFX_ITEM_SET == pDstBox->GetFrmFmt()->GetItemState( RES_BOXATR_VALUE ) )
665 pDstBox->ClaimFrmFmt()->ResetFmtAttr( RES_BOXATR_FORMAT,
666 RES_BOXATR_VALUE );
669 // kopiere die TabellenBoxAttribute - Formel/Format/Value
670 if( pCpyBox )
672 SfxItemSet aBoxAttrSet( pCpyDoc->GetAttrPool(), RES_BOXATR_FORMAT,
673 RES_BOXATR_VALUE );
674 aBoxAttrSet.Put( pCpyBox->GetFrmFmt()->GetAttrSet() );
675 if( aBoxAttrSet.Count() )
677 const SfxPoolItem* pItem;
678 SvNumberFormatter* pN = pDoc->GetNumberFormatter( FALSE );
679 if( pN && pN->HasMergeFmtTbl() && SFX_ITEM_SET == aBoxAttrSet.
680 GetItemState( RES_BOXATR_FORMAT, FALSE, &pItem ) )
682 ULONG nOldIdx = ((SwTblBoxNumFormat*)pItem)->GetValue();
683 ULONG nNewIdx = pN->GetMergeFmtIndex( nOldIdx );
684 if( nNewIdx != nOldIdx )
685 aBoxAttrSet.Put( SwTblBoxNumFormat( nNewIdx ));
687 pDstBox->ClaimFrmFmt()->SetFmtAttr( aBoxAttrSet );
692 pDoc->DoUndo( bUndo );
695 BOOL SwTable::InsNewTable( const SwTable& rCpyTbl, const SwSelBoxes& rSelBoxes,
696 SwUndoTblCpyTbl* pUndo )
698 SwDoc* pDoc = GetFrmFmt()->GetDoc();
699 SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc();
701 SwTblNumFmtMerge aTNFM( *pCpyDoc, *pDoc );
703 // analyse source structure
704 TableStructure aCopyStruct( rCpyTbl );
706 // analyse target structure (from start box) and selected substructure
707 _FndBox aFndBox( 0, 0 );
708 { // get all boxes/lines
709 _FndPara aPara( rSelBoxes, &aFndBox );
710 GetTabLines().ForEach( &_FndLineCopyCol, &aPara );
712 TableStructure aTarget( *this, aFndBox, rSelBoxes, aCopyStruct.getLineCount() );
714 bool bClear = false;
715 if( aTarget.mnAddLine && IsNewModel() )
717 SwSelBoxes aBoxes;
718 aBoxes.Insert( GetTabLines()[ GetTabLines().Count()-1 ]->GetTabBoxes()[0] );
719 if( pUndo )
720 pUndo->InsertRow( *this, aBoxes, aTarget.mnAddLine );
721 else
722 InsertRow( pDoc, aBoxes, aTarget.mnAddLine, TRUE );
724 aTarget.moreLines( *this );
725 bClear = true;
728 // find mapping, if needed extend target table and/or selection
729 aTarget.assignBoxes( aCopyStruct );
732 // Change table formulas into relative representation
733 SwTableFmlUpdate aMsgHnt( &rCpyTbl );
734 aMsgHnt.eFlags = TBL_RELBOXNAME;
735 pCpyDoc->UpdateTblFlds( &aMsgHnt );
738 // delete frames
739 aFndBox.SetTableLines( *this );
740 if( bClear )
741 aFndBox.ClearLineBehind();
742 aFndBox.DelFrms( *this );
744 // copy boxes
745 aTarget.copyBoxes( rCpyTbl, *this, pUndo );
747 // adjust row span attributes accordingly
749 // make frames
750 aFndBox.MakeFrms( *this );
752 return TRUE;
755 // ---------------------------------------------------------------
757 // kopiere die Tabelle in diese.
758 // Kopiere alle Boxen einer Line in entsprechenden Boxen. Der alte Inhalt
759 // wird dabei geloescht.
760 // Ist keine mehr vorhanden, kommt der restliche Inhalt in die letzte
761 // Box einer "GrundLine".
762 // Ist auch keine Line mehr vorhanden, -> auch in die letzte Box
763 // einer "GrundLine"
766 BOOL SwTable::InsTable( const SwTable& rCpyTbl, const SwNodeIndex& rSttBox,
767 SwUndoTblCpyTbl* pUndo )
769 SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen
771 SwDoc* pDoc = GetFrmFmt()->GetDoc();
773 SwTableNode* pTblNd = pDoc->IsIdxInTbl( rSttBox );
775 // suche erstmal die Box, in die kopiert werden soll:
776 SwTableBox* pMyBox = (SwTableBox*)GetTblBox(
777 rSttBox.GetNode().FindTableBoxStartNode()->GetIndex() );
779 ASSERT( pMyBox, "Index steht nicht in dieser Tabelle in einer Box" );
781 // loesche erstmal die Frames der Tabelle
782 _FndBox aFndBox( 0, 0 );
783 aFndBox.DelFrms( pTblNd->GetTable() );
785 SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc();
788 // Tabellen-Formeln in die relative Darstellung umwandeln
789 SwTableFmlUpdate aMsgHnt( &rCpyTbl );
790 aMsgHnt.eFlags = TBL_RELBOXNAME;
791 pCpyDoc->UpdateTblFlds( &aMsgHnt );
794 SwTblNumFmtMerge aTNFM( *pCpyDoc, *pDoc );
796 BOOL bDelCntnt = TRUE;
797 const SwTableBox* pTmp;
799 for( USHORT nLines = 0; nLines < rCpyTbl.GetTabLines().Count(); ++nLines )
801 // hole die erste Box von der Copy-Line
802 const SwTableBox* pCpyBox = rCpyTbl.GetTabLines()[nLines]
803 ->GetTabBoxes()[0];
804 while( pCpyBox->GetTabLines().Count() )
805 pCpyBox = pCpyBox->GetTabLines()[0]->GetTabBoxes()[0];
807 do {
808 // kopiere erst den neuen und loeschen dann den alten Inhalt
809 // (keine leeren Section erzeugen, werden sonst geloescht!)
810 lcl_CpyBox( rCpyTbl, pCpyBox, *this, pMyBox, bDelCntnt, pUndo );
812 if( 0 == (pTmp = pCpyBox->FindNextBox( rCpyTbl, pCpyBox, FALSE )))
813 break; // es folgt keine weitere Box mehr
814 pCpyBox = pTmp;
816 if( 0 == ( pTmp = pMyBox->FindNextBox( *this, pMyBox, FALSE )))
817 bDelCntnt = FALSE; // kein Platz mehr ??
818 else
819 pMyBox = (SwTableBox*)pTmp;
821 } while( TRUE );
823 // suche die oberste Line
824 SwTableLine* pNxtLine = pMyBox->GetUpper();
825 while( pNxtLine->GetUpper() )
826 pNxtLine = pNxtLine->GetUpper()->GetUpper();
827 USHORT nPos = GetTabLines().C40_GETPOS( SwTableLine, pNxtLine );
828 // gibt es eine naechste ??
829 if( nPos + 1 >= GetTabLines().Count() )
830 bDelCntnt = FALSE; // es gibt keine, alles in die letzte Box
831 else
833 // suche die naechste "Inhaltstragende Box"
834 pNxtLine = GetTabLines()[ nPos+1 ];
835 pMyBox = pNxtLine->GetTabBoxes()[0];
836 while( pMyBox->GetTabLines().Count() )
837 pMyBox = pMyBox->GetTabLines()[0]->GetTabBoxes()[0];
838 bDelCntnt = TRUE;
842 aFndBox.MakeFrms( pTblNd->GetTable() ); // erzeuge die Frames neu
843 return TRUE;
847 BOOL SwTable::InsTable( const SwTable& rCpyTbl, const SwSelBoxes& rSelBoxes,
848 SwUndoTblCpyTbl* pUndo )
850 ASSERT( rSelBoxes.Count(), "Missing selection" )
852 SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen
854 if( IsNewModel() || rCpyTbl.IsNewModel() )
855 return InsNewTable( rCpyTbl, rSelBoxes, pUndo );
857 ASSERT( !rCpyTbl.IsTblComplex(), "Table too complex" )
859 SwDoc* pDoc = GetFrmFmt()->GetDoc();
860 SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc();
862 SwTblNumFmtMerge aTNFM( *pCpyDoc, *pDoc );
864 SwTableBox *pTmpBox, *pSttBox = (SwTableBox*)rSelBoxes[0];
866 USHORT nLn, nBx;
867 _FndLine *pFLine, *pInsFLine = 0;
868 _FndBox aFndBox( 0, 0 );
869 // suche alle Boxen / Lines
871 _FndPara aPara( rSelBoxes, &aFndBox );
872 ((SwTableLines&)GetTabLines()).ForEach( &_FndLineCopyCol, &aPara );
875 // JP 06.09.96: Sonderfall - eine Box in der Tabelle -> in alle
876 // selektierten Boxen kopieren!
877 if( 1 != rCpyTbl.GetTabSortBoxes().Count() )
879 SwTableLine* pSttLine = pSttBox->GetUpper();
880 USHORT nSttBox = pSttLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSttBox );
881 USHORT nSttLine = GetTabLines().C40_GETPOS( SwTableLine, pSttLine );
882 _FndBox* pFndBox;
884 USHORT nFndCnt = aFndBox.GetLines().Count();
885 if( !nFndCnt )
886 return FALSE;
888 // teste ob genug Platz fuer die einzelnen Lines und Boxen ist:
889 USHORT nTstLns = 0;
890 pFLine = aFndBox.GetLines()[ 0 ];
891 pSttLine = pFLine->GetLine();
892 nSttLine = GetTabLines().C40_GETPOS( SwTableLine, pSttLine );
893 // sind ueberhaupt soviele Zeilen vorhanden
894 if( 1 == nFndCnt )
896 // in der Tabelle noch genug Platz ??
897 if( (GetTabLines().Count() - nSttLine ) <
898 rCpyTbl.GetTabLines().Count() )
900 // sollte nicht mehr soviele Lines vorhanden sein, dann
901 // teste, ob man durch einfuegen neuer zum Ziel kommt. Aber
902 // nur wenn die SSelection eine Box umfasst !!
903 if( 1 < rSelBoxes.Count() )
904 return FALSE;
906 USHORT nNewLns = rCpyTbl.GetTabLines().Count() -
907 (GetTabLines().Count() - nSttLine );
909 // Dann teste mal ob die Anzahl der Boxen fuer die Lines reicht
910 SwTableLine* pLastLn = GetTabLines()[ GetTabLines().Count()-1 ];
912 pSttBox = pFLine->GetBoxes()[0]->GetBox();
913 nSttBox = pFLine->GetLine()->GetTabBoxes().C40_GETPOS( SwTableBox, pSttBox );
914 for( USHORT n = rCpyTbl.GetTabLines().Count() - nNewLns;
915 n < rCpyTbl.GetTabLines().Count(); ++n )
917 SwTableLine* pCpyLn = rCpyTbl.GetTabLines()[ n ];
919 if( pLastLn->GetTabBoxes().Count() < nSttBox ||
920 ( pLastLn->GetTabBoxes().Count() - nSttBox ) <
921 pCpyLn->GetTabBoxes().Count() )
922 return FALSE;
924 // Test auf Verschachtelungen
925 for( nBx = 0; nBx < pCpyLn->GetTabBoxes().Count(); ++nBx )
926 if( !( pTmpBox = pLastLn->GetTabBoxes()[ nSttBox + nBx ])
927 ->GetSttNd() )
928 return FALSE;
930 // es ist also Platz fuer das zu kopierende vorhanden, also
931 // fuege entsprechend neue Zeilen ein.
932 SwTableBox* pInsBox = pLastLn->GetTabBoxes()[ nSttBox ];
933 ASSERT( pInsBox && pInsBox->GetSttNd(),
934 "kein CntntBox oder steht nicht in dieser Tabelle" );
935 SwSelBoxes aBoxes;
937 if( pUndo
938 ? !pUndo->InsertRow( *this, SelLineFromBox( pInsBox,
939 aBoxes, TRUE ), nNewLns )
940 : !InsertRow( pDoc, SelLineFromBox( pInsBox,
941 aBoxes, TRUE ), nNewLns, TRUE ) )
942 return FALSE;
945 nTstLns = rCpyTbl.GetTabLines().Count(); // soviele Kopieren
947 else if( 0 == (nFndCnt % rCpyTbl.GetTabLines().Count()) )
948 nTstLns = nFndCnt;
949 else
950 return FALSE; // kein Platz fuer die Zeilen
952 for( nLn = 0; nLn < nTstLns; ++nLn )
954 // Zeilen sind genug vorhanden, dann ueberpruefe die Boxen
955 // je Zeile
956 pFLine = aFndBox.GetLines()[ nLn % nFndCnt ];
957 SwTableLine* pLine = pFLine->GetLine();
958 pSttBox = pFLine->GetBoxes()[0]->GetBox();
959 nSttBox = pLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSttBox );
960 if( nLn >= nFndCnt )
962 // es sind im ClipBoard mehr Zeilen als selectiert wurden
963 pInsFLine = new _FndLine( GetTabLines()[ nSttLine + nLn ],
964 &aFndBox );
965 pLine = pInsFLine->GetLine();
967 SwTableLine* pCpyLn = rCpyTbl.GetTabLines()[ nLn %
968 rCpyTbl.GetTabLines().Count() ];
970 // zu wenig Zeilen selektiert ?
971 if( pInsFLine )
973 // eine neue Zeile wird in die FndBox eingefuegt,
974 if( pLine->GetTabBoxes().Count() < nSttBox ||
975 ( pLine->GetTabBoxes().Count() - nSttBox ) <
976 pFLine->GetBoxes().Count() )
977 return FALSE;
979 // Test auf Verschachtelungen
980 for( nBx = 0; nBx < pFLine->GetBoxes().Count(); ++nBx )
982 if( !( pTmpBox = pLine->GetTabBoxes()[ nSttBox + nBx ])
983 ->GetSttNd() )
984 return FALSE;
985 // wenn Ok, fuege die Box in die FndLine zu
986 pFndBox = new _FndBox( pTmpBox, pInsFLine );
987 pInsFLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, nBx );
989 aFndBox.GetLines().C40_INSERT( _FndLine, pInsFLine, nLn );
991 else if( pFLine->GetBoxes().Count() == 1 )
993 if( pLine->GetTabBoxes().Count() < nSttBox ||
994 ( pLine->GetTabBoxes().Count() - nSttBox ) <
995 pCpyLn->GetTabBoxes().Count() )
996 return FALSE;
998 // Test auf Verschachtelungen
999 for( nBx = 0; nBx < pCpyLn->GetTabBoxes().Count(); ++nBx )
1001 if( !( pTmpBox = pLine->GetTabBoxes()[ nSttBox + nBx ])
1002 ->GetSttNd() )
1003 return FALSE;
1004 // wenn Ok, fuege die Box in die FndLine zu
1005 if( nBx == pFLine->GetBoxes().Count() )
1007 pFndBox = new _FndBox( pTmpBox, pFLine );
1008 pFLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, nBx );
1012 else
1014 // ueberpruefe die selektierten Boxen mit denen im Clipboard
1015 // (n-Fach)
1016 if( 0 != ( pFLine->GetBoxes().Count() %
1017 pCpyLn->GetTabBoxes().Count() ))
1018 return FALSE;
1020 // Test auf Verschachtelungen
1021 for( nBx = 0; nBx < pFLine->GetBoxes().Count(); ++nBx )
1022 if( !pFLine->GetBoxes()[ nBx ]->GetBox()->GetSttNd() )
1023 return FALSE;
1027 if( !aFndBox.GetLines().Count() )
1028 return FALSE;
1032 // Tabellen-Formeln in die relative Darstellung umwandeln
1033 SwTableFmlUpdate aMsgHnt( &rCpyTbl );
1034 aMsgHnt.eFlags = TBL_RELBOXNAME;
1035 pCpyDoc->UpdateTblFlds( &aMsgHnt );
1038 // loesche die Frames
1039 aFndBox.SetTableLines( *this );
1040 aFndBox.DelFrms( *this );
1042 if( 1 == rCpyTbl.GetTabSortBoxes().Count() )
1044 SwTableBox *pTmpBx = rCpyTbl.GetTabSortBoxes()[0];
1045 for( USHORT n = 0; n < rSelBoxes.Count(); ++n )
1046 lcl_CpyBox( rCpyTbl, pTmpBx, *this,
1047 (SwTableBox*)rSelBoxes[n], TRUE, pUndo );
1049 else
1050 for( nLn = 0; nLn < aFndBox.GetLines().Count(); ++nLn )
1052 pFLine = aFndBox.GetLines()[ nLn ];
1053 SwTableLine* pCpyLn = rCpyTbl.GetTabLines()[
1054 nLn % rCpyTbl.GetTabLines().Count() ];
1055 for( nBx = 0; nBx < pFLine->GetBoxes().Count(); ++nBx )
1057 // Kopiere in pMyBox die pCpyBox
1058 lcl_CpyBox( rCpyTbl, pCpyLn->GetTabBoxes()[
1059 nBx % pCpyLn->GetTabBoxes().Count() ],
1060 *this, pFLine->GetBoxes()[ nBx ]->GetBox(), TRUE, pUndo );
1064 aFndBox.MakeFrms( *this );
1065 return TRUE;
1070 BOOL _FndCntntBox( const SwTableBox*& rpBox, void* pPara )
1072 SwTableBox* pBox = (SwTableBox*)rpBox;
1073 if( rpBox->GetTabLines().Count() )
1074 pBox->GetTabLines().ForEach( &_FndCntntLine, pPara );
1075 else
1076 ((SwSelBoxes*)pPara)->Insert( pBox );
1077 return TRUE;
1081 BOOL _FndCntntLine( const SwTableLine*& rpLine, void* pPara )
1083 ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &_FndCntntBox, pPara );
1084 return TRUE;
1088 // suche alle Inhaltstragenden-Boxen dieser Box
1089 SwSelBoxes& SwTable::SelLineFromBox( const SwTableBox* pBox,
1090 SwSelBoxes& rBoxes, BOOL bToTop ) const
1092 SwTableLine* pLine = (SwTableLine*)pBox->GetUpper();
1093 if( bToTop )
1094 while( pLine->GetUpper() )
1095 pLine = pLine->GetUpper()->GetUpper();
1097 // alle alten loeschen
1098 rBoxes.Remove( USHORT(0), rBoxes.Count() );
1099 pLine->GetTabBoxes().ForEach( &_FndCntntBox, &rBoxes );
1100 return rBoxes;