1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_sw.hxx" 30 31 32 #include <hintids.hxx> 33 34 #define _ZFORLIST_DECLARE_TABLE 35 #include <svl/zforlist.hxx> 36 #include <frmfmt.hxx> 37 #include <doc.hxx> 38 #include <IDocumentUndoRedo.hxx> 39 #include <cntfrm.hxx> 40 #include <pam.hxx> 41 #include <swtable.hxx> 42 #include <ndtxt.hxx> 43 #include <fldbas.hxx> 44 #include <tblsel.hxx> 45 #include <tabfrm.hxx> 46 #include <poolfmt.hxx> 47 #include <cellatr.hxx> 48 #include <mvsave.hxx> 49 #include <docary.hxx> 50 #include <fmtanchr.hxx> 51 #include <hints.hxx> 52 #include <UndoTable.hxx> 53 #include <redline.hxx> 54 #include <fmtfsize.hxx> 55 #include <list> 56 57 sal_Bool _FndCntntLine( const SwTableLine*& rpLine, void* pPara ); 58 sal_Bool _FndCntntBox( const SwTableBox*& rpBox, void* pPara ); 59 void lcl_CpyBox( const SwTable& rCpyTbl, const SwTableBox* pCpyBox, 60 SwTable& rDstTbl, SwTableBox* pDstBox, 61 sal_Bool bDelCntnt, SwUndoTblCpyTbl* pUndo ); 62 63 // The following type will be used by table copy functions to describe 64 // the structure of tables (or parts of tables). 65 // It's for new table model only. 66 67 namespace 68 { 69 struct BoxSpanInfo 70 { 71 SwTableBox* mpBox; 72 SwTableBox* mpCopy; 73 sal_uInt16 mnColSpan; 74 bool mbSelected; 75 }; 76 77 typedef std::vector< BoxSpanInfo > BoxStructure; 78 typedef std::vector< BoxStructure > LineStructure; 79 typedef std::list< sal_uLong > ColumnStructure; 80 81 struct SubBox 82 { 83 SwTableBox *mpBox; 84 bool mbCovered; 85 }; 86 87 typedef std::list< SubBox > SubLine; 88 typedef std::list< SubLine > SubTable; 89 90 class TableStructure 91 { 92 public: 93 LineStructure maLines; 94 ColumnStructure maCols; 95 sal_uInt16 mnStartCol; 96 sal_uInt16 mnAddLine; 97 void addLine( sal_uInt16 &rLine, const SwTableBoxes&, const SwSelBoxes*, 98 bool bNewModel ); 99 void addBox( sal_uInt16 nLine, const SwSelBoxes*, SwTableBox *pBox, 100 sal_uLong &rnB, sal_uInt16 &rnC, ColumnStructure::iterator& rpCl, 101 BoxStructure::iterator& rpSel, bool &rbSel, bool bCover ); 102 void incColSpan( sal_uInt16 nLine, sal_uInt16 nCol ); 103 TableStructure( const SwTable& rTable ); 104 TableStructure( const SwTable& rTable, _FndBox &rFndBox, 105 const SwSelBoxes& rSelBoxes, 106 LineStructure::size_type nMinSize ); 107 LineStructure::size_type getLineCount() const 108 { return maLines.size(); } 109 void moreLines( const SwTable& rTable ); 110 void assignBoxes( const TableStructure &rSource ); 111 void copyBoxes( const SwTable& rSource, SwTable& rDstTbl, 112 SwUndoTblCpyTbl* pUndo ) const; 113 }; 114 115 SubTable::iterator insertSubLine( SubTable& rSubTable, SwTableLine& rLine, 116 SubTable::iterator pStartLn ); 117 118 SubTable::iterator insertSubBox( SubTable& rSubTable, SwTableBox& rBox, 119 SubTable::iterator pStartLn, SubTable::iterator pEndLn ) 120 { 121 if( rBox.GetTabLines().Count() ) 122 { 123 SubTable::difference_type nSize = std::distance( pStartLn, pEndLn ); 124 if( nSize < rBox.GetTabLines().Count() ) 125 { 126 SubLine aSubLine; 127 SubLine::iterator pBox = pStartLn->begin(); 128 SubLine::iterator pEnd = pStartLn->end(); 129 while( pBox != pEnd ) 130 { 131 SubBox aSub; 132 aSub.mpBox = pBox->mpBox; 133 aSub.mbCovered = true; 134 aSubLine.push_back( aSub ); 135 ++pBox; 136 } 137 do 138 { 139 rSubTable.insert( pEndLn, aSubLine ); 140 } while( ++nSize < rBox.GetTabLines().Count() ); 141 } 142 for( sal_uInt16 nLine = 0; nLine < rBox.GetTabLines().Count(); ++nLine ) 143 pStartLn = insertSubLine( rSubTable, *rBox.GetTabLines()[nLine], 144 pStartLn ); 145 ASSERT( pStartLn == pEndLn, "Sub line confusion" ); 146 } 147 else 148 { 149 SubBox aSub; 150 aSub.mpBox = &rBox; 151 aSub.mbCovered = false; 152 while( pStartLn != pEndLn ) 153 { 154 pStartLn->push_back( aSub ); 155 aSub.mbCovered = true; 156 ++pStartLn; 157 } 158 } 159 return pStartLn; 160 } 161 162 SubTable::iterator insertSubLine( SubTable& rSubTable, SwTableLine& rLine, 163 SubTable::iterator pStartLn ) 164 { 165 SubTable::iterator pMax = pStartLn; 166 ++pMax; 167 SubTable::difference_type nMax = 1; 168 for( sal_uInt16 nBox = 0; nBox < rLine.GetTabBoxes().Count(); ++nBox ) 169 { 170 SubTable::iterator pTmp = insertSubBox( rSubTable, 171 *rLine.GetTabBoxes()[nBox], pStartLn, pMax ); 172 SubTable::difference_type nTmp = std::distance( pStartLn, pTmp ); 173 if( nTmp > nMax ) 174 { 175 pMax = pTmp; 176 nMax = nTmp; 177 } 178 } 179 return pMax; 180 } 181 182 TableStructure::TableStructure( const SwTable& rTable ) : 183 maLines( rTable.GetTabLines().Count() ), mnStartCol(USHRT_MAX), 184 mnAddLine(0) 185 { 186 maCols.push_front(0); 187 const SwTableLines &rLines = rTable.GetTabLines(); 188 sal_uInt16 nCnt = 0; 189 for( sal_uInt16 nLine = 0; nLine < rLines.Count(); ++nLine ) 190 addLine( nCnt, rLines[nLine]->GetTabBoxes(), 0, rTable.IsNewModel() ); 191 } 192 193 TableStructure::TableStructure( const SwTable& rTable, 194 _FndBox &rFndBox, const SwSelBoxes& rSelBoxes, 195 LineStructure::size_type nMinSize ) 196 : mnStartCol(USHRT_MAX), mnAddLine(0) 197 { 198 if( rFndBox.GetLines().Count() ) 199 { 200 bool bNoSelection = rSelBoxes.Count() < 2; 201 _FndLines &rFndLines = rFndBox.GetLines(); 202 maCols.push_front(0); 203 const SwTableLine* pLine = rFndLines[0]->GetLine(); 204 sal_uInt16 nStartLn = rTable.GetTabLines().C40_GETPOS( SwTableLine, pLine ); 205 sal_uInt16 nEndLn = nStartLn; 206 if( rFndLines.Count() > 1 ) 207 { 208 pLine = rFndLines[ rFndLines.Count()-1 ]->GetLine(); 209 nEndLn = rTable.GetTabLines().C40_GETPOS( SwTableLine, pLine ); 210 } 211 if( nStartLn < USHRT_MAX && nEndLn < USHRT_MAX ) 212 { 213 const SwTableLines &rLines = rTable.GetTabLines(); 214 if( bNoSelection && 215 (sal_uInt16)nMinSize > nEndLn - nStartLn + 1 ) 216 { 217 sal_uInt16 nNewEndLn = nStartLn + (sal_uInt16)nMinSize - 1; 218 if( nNewEndLn >= rLines.Count() ) 219 { 220 mnAddLine = nNewEndLn - rLines.Count() + 1; 221 nNewEndLn = rLines.Count() - 1; 222 } 223 while( nEndLn < nNewEndLn ) 224 { 225 SwTableLine *pLine2 = rLines[ ++nEndLn ]; 226 SwTableBox *pTmpBox = pLine2->GetTabBoxes()[0]; 227 _FndLine *pInsLine = new _FndLine( pLine2, &rFndBox ); 228 _FndBox *pFndBox = new _FndBox( pTmpBox, pInsLine ); 229 pInsLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, 0 ); 230 rFndLines.C40_INSERT( _FndLine, pInsLine, rFndLines.Count() ); 231 } 232 } 233 maLines.resize( nEndLn - nStartLn + 1 ); 234 const SwSelBoxes* pSelBoxes = &rSelBoxes; 235 sal_uInt16 nCnt = 0; 236 for( sal_uInt16 nLine = nStartLn; nLine <= nEndLn; ++nLine ) 237 { 238 addLine( nCnt, rLines[nLine]->GetTabBoxes(), 239 pSelBoxes, rTable.IsNewModel() ); 240 if( bNoSelection ) 241 pSelBoxes = 0; 242 } 243 } 244 if( bNoSelection && mnStartCol < USHRT_MAX ) 245 { 246 BoxStructure::iterator pC = maLines[0].begin(); 247 BoxStructure::iterator pEnd = maLines[0].end(); 248 sal_uInt16 nIdx = mnStartCol; 249 mnStartCol = 0; 250 while( nIdx && pC != pEnd ) 251 { 252 mnStartCol = mnStartCol + pC->mnColSpan; 253 --nIdx; 254 ++pC; 255 } 256 } 257 else 258 mnStartCol = USHRT_MAX; 259 } 260 } 261 262 void TableStructure::addLine( sal_uInt16 &rLine, const SwTableBoxes& rBoxes, 263 const SwSelBoxes* pSelBoxes, bool bNewModel ) 264 { 265 bool bComplex = false; 266 if( !bNewModel ) 267 for( sal_uInt16 nBox = 0; !bComplex && nBox < rBoxes.Count(); ++nBox ) 268 bComplex = rBoxes[nBox]->GetTabLines().Count() > 0; 269 if( bComplex ) 270 { 271 SubTable aSubTable; 272 SubLine aSubLine; 273 aSubTable.push_back( aSubLine ); 274 SubTable::iterator pStartLn = aSubTable.begin(); 275 SubTable::iterator pEndLn = aSubTable.end(); 276 for( sal_uInt16 nBox = 0; nBox < rBoxes.Count(); ++nBox ) 277 insertSubBox( aSubTable, *rBoxes[nBox], pStartLn, pEndLn ); 278 SubTable::size_type nSize = aSubTable.size(); 279 if( nSize ) 280 { 281 maLines.resize( maLines.size() + nSize - 1 ); 282 while( pStartLn != pEndLn ) 283 { 284 bool bSelected = false; 285 sal_uLong nBorder = 0; 286 sal_uInt16 nCol = 0; 287 maLines[rLine].reserve( pStartLn->size() ); 288 BoxStructure::iterator pSel = maLines[rLine].end(); 289 ColumnStructure::iterator pCol = maCols.begin(); 290 SubLine::iterator pBox = pStartLn->begin(); 291 SubLine::iterator pEnd = pStartLn->end(); 292 while( pBox != pEnd ) 293 { 294 addBox( rLine, pSelBoxes, pBox->mpBox, nBorder, nCol, 295 pCol, pSel, bSelected, pBox->mbCovered ); 296 ++pBox; 297 } 298 ++rLine; 299 ++pStartLn; 300 } 301 } 302 } 303 else 304 { 305 bool bSelected = false; 306 sal_uLong nBorder = 0; 307 sal_uInt16 nCol = 0; 308 maLines[rLine].reserve( rBoxes.Count() ); 309 ColumnStructure::iterator pCol = maCols.begin(); 310 BoxStructure::iterator pSel = maLines[rLine].end(); 311 for( sal_uInt16 nBox = 0; nBox < rBoxes.Count(); ++nBox ) 312 addBox( rLine, pSelBoxes, rBoxes[nBox], nBorder, nCol, 313 pCol, pSel, bSelected, false ); 314 ++rLine; 315 } 316 } 317 318 void TableStructure::addBox( sal_uInt16 nLine, const SwSelBoxes* pSelBoxes, 319 SwTableBox *pBox, sal_uLong &rnBorder, sal_uInt16 &rnCol, 320 ColumnStructure::iterator& rpCol, BoxStructure::iterator& rpSel, 321 bool &rbSelected, bool bCovered ) 322 { 323 BoxSpanInfo aInfo; 324 if( pSelBoxes && 325 USHRT_MAX != pSelBoxes->GetPos( pBox ) ) 326 { 327 aInfo.mbSelected = true; 328 if( mnStartCol == USHRT_MAX ) 329 { 330 mnStartCol = (sal_uInt16)maLines[nLine].size(); 331 if( pSelBoxes->Count() < 2 ) 332 { 333 pSelBoxes = 0; 334 aInfo.mbSelected = false; 335 } 336 } 337 } 338 else 339 aInfo.mbSelected = false; 340 rnBorder += pBox->GetFrmFmt()->GetFrmSize().GetWidth(); 341 sal_uInt16 nLeftCol = rnCol; 342 while( rpCol != maCols.end() && *rpCol < rnBorder ) 343 { 344 ++rnCol; 345 ++rpCol; 346 } 347 if( rpCol == maCols.end() || *rpCol > rnBorder ) 348 { 349 maCols.insert( rpCol, rnBorder ); 350 --rpCol; 351 incColSpan( nLine, rnCol ); 352 } 353 aInfo.mnColSpan = rnCol - nLeftCol; 354 aInfo.mpCopy = 0; 355 aInfo.mpBox = bCovered ? 0 : pBox; 356 maLines[nLine].push_back( aInfo ); 357 if( aInfo.mbSelected ) 358 { 359 if( rbSelected ) 360 { 361 while( rpSel != maLines[nLine].end() ) 362 { 363 rpSel->mbSelected = true; 364 ++rpSel; 365 } 366 } 367 else 368 { 369 rpSel = maLines[nLine].end(); 370 rbSelected = true; 371 } 372 --rpSel; 373 } 374 } 375 376 void TableStructure::moreLines( const SwTable& rTable ) 377 { 378 if( mnAddLine ) 379 { 380 const SwTableLines &rLines = rTable.GetTabLines(); 381 sal_uInt16 nLineCount = rLines.Count(); 382 if( nLineCount < mnAddLine ) 383 mnAddLine = nLineCount; 384 sal_uInt16 nLine = (sal_uInt16)maLines.size(); 385 maLines.resize( nLine + mnAddLine ); 386 while( mnAddLine ) 387 { 388 SwTableLine *pLine = rLines[ nLineCount - mnAddLine ]; 389 addLine( nLine, pLine->GetTabBoxes(), 0, rTable.IsNewModel() ); 390 --mnAddLine; 391 } 392 } 393 } 394 395 void TableStructure::incColSpan( sal_uInt16 nLineMax, sal_uInt16 nNewCol ) 396 { 397 for( sal_uInt16 nLine = 0; nLine < nLineMax; ++nLine ) 398 { 399 BoxStructure::iterator pInfo = maLines[nLine].begin(); 400 BoxStructure::iterator pEnd = maLines[nLine].end(); 401 long nCol = pInfo->mnColSpan; 402 while( nNewCol > nCol && ++pInfo != pEnd ) 403 nCol += pInfo->mnColSpan; 404 if( pInfo != pEnd ) 405 ++(pInfo->mnColSpan); 406 } 407 } 408 409 void TableStructure::assignBoxes( const TableStructure &rSource ) 410 { 411 LineStructure::const_iterator pFirstLine = rSource.maLines.begin(); 412 LineStructure::const_iterator pLastLine = rSource.maLines.end(); 413 if( pFirstLine == pLastLine ) 414 return; 415 LineStructure::const_iterator pCurrLine = pFirstLine; 416 LineStructure::size_type nLineCount = maLines.size(); 417 sal_uInt16 nFirstStartCol = 0; 418 { 419 BoxStructure::const_iterator pFirstBox = pFirstLine->begin(); 420 if( pFirstBox != pFirstLine->end() && pFirstBox->mpBox && 421 pFirstBox->mpBox->getDummyFlag() ) 422 nFirstStartCol = pFirstBox->mnColSpan; 423 } 424 for( LineStructure::size_type nLine = 0; nLine < nLineCount; ++nLine ) 425 { 426 BoxStructure::const_iterator pFirstBox = pCurrLine->begin(); 427 BoxStructure::const_iterator pLastBox = pCurrLine->end(); 428 sal_uInt16 nCurrStartCol = mnStartCol; 429 if( pFirstBox != pLastBox ) 430 { 431 BoxStructure::const_iterator pTmpBox = pLastBox; 432 --pTmpBox; 433 if( pTmpBox->mpBox && pTmpBox->mpBox->getDummyFlag() ) 434 --pLastBox; 435 if( pFirstBox != pLastBox && pFirstBox->mpBox && 436 pFirstBox->mpBox->getDummyFlag() ) 437 { 438 if( nCurrStartCol < USHRT_MAX ) 439 { 440 if( pFirstBox->mnColSpan > nFirstStartCol ) 441 nCurrStartCol = pFirstBox->mnColSpan - nFirstStartCol 442 + nCurrStartCol; 443 } 444 ++pFirstBox; 445 } 446 } 447 if( pFirstBox != pLastBox ) 448 { 449 BoxStructure::const_iterator pCurrBox = pFirstBox; 450 BoxStructure &rBox = maLines[nLine]; 451 BoxStructure::size_type nBoxCount = rBox.size(); 452 sal_uInt16 nCol = 0; 453 for( BoxStructure::size_type nBox = 0; nBox < nBoxCount; ++nBox ) 454 { 455 BoxSpanInfo& rInfo = rBox[nBox]; 456 nCol = nCol + rInfo.mnColSpan; 457 if( rInfo.mbSelected || nCol > nCurrStartCol ) 458 { 459 rInfo.mpCopy = pCurrBox->mpBox; 460 if( rInfo.mbSelected && rInfo.mpCopy->getDummyFlag() ) 461 { 462 ++pCurrBox; 463 if( pCurrBox == pLastBox ) 464 { 465 pCurrBox = pFirstBox; 466 if( pCurrBox->mpBox->getDummyFlag() ) 467 ++pCurrBox; 468 } 469 rInfo.mpCopy = pCurrBox->mpBox; 470 } 471 ++pCurrBox; 472 if( pCurrBox == pLastBox ) 473 { 474 if( rInfo.mbSelected ) 475 pCurrBox = pFirstBox; 476 else 477 { 478 rInfo.mbSelected = rInfo.mpCopy == 0; 479 break; 480 } 481 } 482 rInfo.mbSelected = rInfo.mpCopy == 0; 483 } 484 } 485 } 486 ++pCurrLine; 487 if( pCurrLine == pLastLine ) 488 pCurrLine = pFirstLine; 489 } 490 } 491 492 void TableStructure::copyBoxes( const SwTable& rSource, SwTable& rDstTbl, 493 SwUndoTblCpyTbl* pUndo ) const 494 { 495 LineStructure::size_type nLineCount = maLines.size(); 496 for( LineStructure::size_type nLine = 0; nLine < nLineCount; ++nLine ) 497 { 498 const BoxStructure &rBox = maLines[nLine]; 499 BoxStructure::size_type nBoxCount = rBox.size(); 500 for( BoxStructure::size_type nBox = 0; nBox < nBoxCount; ++nBox ) 501 { 502 const BoxSpanInfo& rInfo = rBox[nBox]; 503 if( ( rInfo.mpCopy && !rInfo.mpCopy->getDummyFlag() ) 504 || rInfo.mbSelected ) 505 { 506 SwTableBox *pBox = rInfo.mpBox; 507 if( pBox && pBox->getRowSpan() > 0 ) 508 lcl_CpyBox( rSource, rInfo.mpCopy, rDstTbl, pBox, 509 sal_True, pUndo ); 510 /* Idea: If target cell is a covered cell, append content 511 to master cell. 512 sal_Bool bReplace = sal_True; 513 if( pBox->getRowSpan() < 0 ) 514 { 515 if( rInfo.mpCopy->getRowSpan() < 0 ) 516 continue; 517 pBox = &pBox->FindStartOfRowSpan( rDstTbl ); 518 bReplace = sal_False; 519 } 520 lcl_CpyBox( rSource, rInfo.mpCopy, rDstTbl, pBox, 521 bReplace, pUndo ); 522 */ 523 } 524 } 525 } 526 } 527 } 528 529 // --------------------------------------------------------------- 530 531 // kopiere die Tabelle in diese. 532 // Kopiere alle Boxen einer Line in entsprechenden Boxen. Der alte Inhalt 533 // wird dabei geloescht. 534 // Ist keine mehr vorhanden, kommt der restliche Inhalt in die letzte 535 // Box einer "GrundLine". 536 // Ist auch keine Line mehr vorhanden, -> auch in die letzte Box 537 // einer "GrundLine" 538 539 540 void lcl_CpyBox( const SwTable& rCpyTbl, const SwTableBox* pCpyBox, 541 SwTable& rDstTbl, SwTableBox* pDstBox, 542 sal_Bool bDelCntnt, SwUndoTblCpyTbl* pUndo ) 543 { 544 ASSERT( ( !pCpyBox || pCpyBox->GetSttNd() ) && pDstBox->GetSttNd(), 545 "Keine inhaltstragende Box" ); 546 547 SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc(); 548 SwDoc* pDoc = rDstTbl.GetFrmFmt()->GetDoc(); 549 550 // kopiere erst den neuen und loeschen dann den alten Inhalt 551 // (keine leeren Section erzeugen; werden sonst geloescht!) 552 std::auto_ptr< SwNodeRange > pRg( pCpyBox ? 553 new SwNodeRange ( *pCpyBox->GetSttNd(), 1, 554 *pCpyBox->GetSttNd()->EndOfSectionNode() ) : 0 ); 555 556 SwNodeIndex aInsIdx( *pDstBox->GetSttNd(), bDelCntnt ? 1 : 557 pDstBox->GetSttNd()->EndOfSectionIndex() - 558 pDstBox->GetSttIdx() ); 559 560 if( pUndo ) 561 pUndo->AddBoxBefore( *pDstBox, bDelCntnt ); 562 563 bool bUndoRedline = pUndo && pDoc->IsRedlineOn(); 564 ::sw::UndoGuard const undoGuard(pDoc->GetIDocumentUndoRedo()); 565 566 SwNodeIndex aSavePos( aInsIdx, -1 ); 567 if( pRg.get() ) 568 pCpyDoc->CopyWithFlyInFly( *pRg, 0, aInsIdx, sal_False ); 569 else 570 pDoc->GetNodes().MakeTxtNode( aInsIdx, (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl() ); 571 aSavePos++; 572 573 SwTableLine* pLine = pDstBox->GetUpper(); 574 while( pLine->GetUpper() ) 575 pLine = pLine->GetUpper()->GetUpper(); 576 577 sal_Bool bReplaceColl = sal_True; 578 if( bDelCntnt && !bUndoRedline ) 579 { 580 // zuerst die Fly loeschen, dann die entsprechenden Nodes 581 SwNodeIndex aEndNdIdx( *aInsIdx.GetNode().EndOfSectionNode() ); 582 583 // Bookmarks usw. verschieben 584 { 585 SwPosition aMvPos( aInsIdx ); 586 SwCntntNode* pCNd = pDoc->GetNodes().GoPrevious( &aMvPos.nNode ); 587 aMvPos.nContent.Assign( pCNd, pCNd->Len() ); 588 pDoc->CorrAbs( aInsIdx, aEndNdIdx, aMvPos, /*sal_True*/sal_False ); 589 } 590 591 // stehen noch FlyFrames rum, loesche auch diese 592 for( sal_uInt16 n = 0; n < pDoc->GetSpzFrmFmts()->Count(); ++n ) 593 { 594 SwFrmFmt *const pFly = (*pDoc->GetSpzFrmFmts())[n]; 595 SwFmtAnchor const*const pAnchor = &pFly->GetAnchor(); 596 SwPosition const*const pAPos = pAnchor->GetCntntAnchor(); 597 if (pAPos && 598 ((FLY_AT_PARA == pAnchor->GetAnchorId()) || 599 (FLY_AT_CHAR == pAnchor->GetAnchorId())) && 600 aInsIdx <= pAPos->nNode && pAPos->nNode <= aEndNdIdx ) 601 { 602 pDoc->DelLayoutFmt( pFly ); 603 } 604 } 605 606 // ist DestBox eine Headline-Box und hat Tabellen-Vorlage gesetzt, 607 // dann NICHT die TabellenHeadline-Vorlage automatisch setzen 608 if( 1 < rDstTbl.GetTabLines().Count() && 609 pLine == rDstTbl.GetTabLines()[0] ) 610 { 611 SwCntntNode* pCNd = aInsIdx.GetNode().GetCntntNode(); 612 if( !pCNd ) 613 { 614 SwNodeIndex aTmp( aInsIdx ); 615 pCNd = pDoc->GetNodes().GoNext( &aTmp ); 616 } 617 618 if( pCNd && 619 /*RES_POOLCOLL_TABLE == */ 620 RES_POOLCOLL_TABLE_HDLN != 621 pCNd->GetFmtColl()->GetPoolFmtId() ) 622 bReplaceColl = sal_False; 623 } 624 625 pDoc->GetNodes().Delete( aInsIdx, aEndNdIdx.GetIndex() - aInsIdx.GetIndex() ); 626 } 627 628 //b6341295: Table copy redlining will be managed by AddBoxAfter() 629 if( pUndo ) 630 pUndo->AddBoxAfter( *pDstBox, aInsIdx, bDelCntnt ); 631 632 // heading 633 SwTxtNode *const pTxtNd = aSavePos.GetNode().GetTxtNode(); 634 if( pTxtNd ) 635 { 636 sal_uInt16 nPoolId = pTxtNd->GetTxtColl()->GetPoolFmtId(); 637 if( bReplaceColl && 638 (( 1 < rDstTbl.GetTabLines().Count() && 639 pLine == rDstTbl.GetTabLines()[0] ) 640 // gilt noch die Tabellen-Inhalt ?? 641 ? RES_POOLCOLL_TABLE == nPoolId 642 : RES_POOLCOLL_TABLE_HDLN == nPoolId ) ) 643 { 644 SwTxtFmtColl* pColl = pDoc->GetTxtCollFromPool( 645 static_cast<sal_uInt16>( 646 RES_POOLCOLL_TABLE == nPoolId 647 ? RES_POOLCOLL_TABLE_HDLN 648 : RES_POOLCOLL_TABLE ) ); 649 if( pColl ) // Vorlage umsetzen 650 { 651 SwPaM aPam( aSavePos ); 652 aPam.SetMark(); 653 aPam.Move( fnMoveForward, fnGoSection ); 654 pDoc->SetTxtFmtColl( aPam, pColl ); 655 } 656 } 657 658 // loesche die akt. Formel/Format/Value Werte 659 if( SFX_ITEM_SET == pDstBox->GetFrmFmt()->GetItemState( RES_BOXATR_FORMAT ) || 660 SFX_ITEM_SET == pDstBox->GetFrmFmt()->GetItemState( RES_BOXATR_FORMULA ) || 661 SFX_ITEM_SET == pDstBox->GetFrmFmt()->GetItemState( RES_BOXATR_VALUE ) ) 662 { 663 pDstBox->ClaimFrmFmt()->ResetFmtAttr( RES_BOXATR_FORMAT, 664 RES_BOXATR_VALUE ); 665 } 666 667 // kopiere die TabellenBoxAttribute - Formel/Format/Value 668 if( pCpyBox ) 669 { 670 SfxItemSet aBoxAttrSet( pCpyDoc->GetAttrPool(), RES_BOXATR_FORMAT, 671 RES_BOXATR_VALUE ); 672 aBoxAttrSet.Put( pCpyBox->GetFrmFmt()->GetAttrSet() ); 673 if( aBoxAttrSet.Count() ) 674 { 675 const SfxPoolItem* pItem; 676 SvNumberFormatter* pN = pDoc->GetNumberFormatter( sal_False ); 677 if( pN && pN->HasMergeFmtTbl() && SFX_ITEM_SET == aBoxAttrSet. 678 GetItemState( RES_BOXATR_FORMAT, sal_False, &pItem ) ) 679 { 680 sal_uLong nOldIdx = ((SwTblBoxNumFormat*)pItem)->GetValue(); 681 sal_uLong nNewIdx = pN->GetMergeFmtIndex( nOldIdx ); 682 if( nNewIdx != nOldIdx ) 683 aBoxAttrSet.Put( SwTblBoxNumFormat( nNewIdx )); 684 } 685 pDstBox->ClaimFrmFmt()->SetFmtAttr( aBoxAttrSet ); 686 } 687 } 688 } 689 } 690 691 sal_Bool SwTable::InsNewTable( const SwTable& rCpyTbl, const SwSelBoxes& rSelBoxes, 692 SwUndoTblCpyTbl* pUndo ) 693 { 694 SwDoc* pDoc = GetFrmFmt()->GetDoc(); 695 SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc(); 696 697 SwTblNumFmtMerge aTNFM( *pCpyDoc, *pDoc ); 698 699 // analyse source structure 700 TableStructure aCopyStruct( rCpyTbl ); 701 702 // analyse target structure (from start box) and selected substructure 703 _FndBox aFndBox( 0, 0 ); 704 { // get all boxes/lines 705 _FndPara aPara( rSelBoxes, &aFndBox ); 706 GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); 707 } 708 TableStructure aTarget( *this, aFndBox, rSelBoxes, aCopyStruct.getLineCount() ); 709 710 bool bClear = false; 711 if( aTarget.mnAddLine && IsNewModel() ) 712 { 713 SwSelBoxes aBoxes; 714 aBoxes.Insert( GetTabLines()[ GetTabLines().Count()-1 ]->GetTabBoxes()[0] ); 715 if( pUndo ) 716 pUndo->InsertRow( *this, aBoxes, aTarget.mnAddLine ); 717 else 718 InsertRow( pDoc, aBoxes, aTarget.mnAddLine, sal_True ); 719 720 aTarget.moreLines( *this ); 721 bClear = true; 722 } 723 724 // find mapping, if needed extend target table and/or selection 725 aTarget.assignBoxes( aCopyStruct ); 726 727 { 728 // Change table formulas into relative representation 729 SwTableFmlUpdate aMsgHnt( &rCpyTbl ); 730 aMsgHnt.eFlags = TBL_RELBOXNAME; 731 pCpyDoc->UpdateTblFlds( &aMsgHnt ); 732 } 733 734 // delete frames 735 aFndBox.SetTableLines( *this ); 736 if( bClear ) 737 aFndBox.ClearLineBehind(); 738 aFndBox.DelFrms( *this ); 739 740 // copy boxes 741 aTarget.copyBoxes( rCpyTbl, *this, pUndo ); 742 743 // adjust row span attributes accordingly 744 745 // make frames 746 aFndBox.MakeFrms( *this ); 747 748 return sal_True; 749 } 750 751 // --------------------------------------------------------------- 752 753 // kopiere die Tabelle in diese. 754 // Kopiere alle Boxen einer Line in entsprechenden Boxen. Der alte Inhalt 755 // wird dabei geloescht. 756 // Ist keine mehr vorhanden, kommt der restliche Inhalt in die letzte 757 // Box einer "GrundLine". 758 // Ist auch keine Line mehr vorhanden, -> auch in die letzte Box 759 // einer "GrundLine" 760 761 762 sal_Bool SwTable::InsTable( const SwTable& rCpyTbl, const SwNodeIndex& rSttBox, 763 SwUndoTblCpyTbl* pUndo ) 764 { 765 SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen 766 767 SwDoc* pDoc = GetFrmFmt()->GetDoc(); 768 769 SwTableNode* pTblNd = pDoc->IsIdxInTbl( rSttBox ); 770 771 // suche erstmal die Box, in die kopiert werden soll: 772 SwTableBox* pMyBox = (SwTableBox*)GetTblBox( 773 rSttBox.GetNode().FindTableBoxStartNode()->GetIndex() ); 774 775 ASSERT( pMyBox, "Index steht nicht in dieser Tabelle in einer Box" ); 776 777 // loesche erstmal die Frames der Tabelle 778 _FndBox aFndBox( 0, 0 ); 779 aFndBox.DelFrms( pTblNd->GetTable() ); 780 781 SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc(); 782 783 { 784 // Tabellen-Formeln in die relative Darstellung umwandeln 785 SwTableFmlUpdate aMsgHnt( &rCpyTbl ); 786 aMsgHnt.eFlags = TBL_RELBOXNAME; 787 pCpyDoc->UpdateTblFlds( &aMsgHnt ); 788 } 789 790 SwTblNumFmtMerge aTNFM( *pCpyDoc, *pDoc ); 791 792 sal_Bool bDelCntnt = sal_True; 793 const SwTableBox* pTmp; 794 795 for( sal_uInt16 nLines = 0; nLines < rCpyTbl.GetTabLines().Count(); ++nLines ) 796 { 797 // hole die erste Box von der Copy-Line 798 const SwTableBox* pCpyBox = rCpyTbl.GetTabLines()[nLines] 799 ->GetTabBoxes()[0]; 800 while( pCpyBox->GetTabLines().Count() ) 801 pCpyBox = pCpyBox->GetTabLines()[0]->GetTabBoxes()[0]; 802 803 do { 804 // kopiere erst den neuen und loeschen dann den alten Inhalt 805 // (keine leeren Section erzeugen, werden sonst geloescht!) 806 lcl_CpyBox( rCpyTbl, pCpyBox, *this, pMyBox, bDelCntnt, pUndo ); 807 808 if( 0 == (pTmp = pCpyBox->FindNextBox( rCpyTbl, pCpyBox, sal_False ))) 809 break; // es folgt keine weitere Box mehr 810 pCpyBox = pTmp; 811 812 if( 0 == ( pTmp = pMyBox->FindNextBox( *this, pMyBox, sal_False ))) 813 bDelCntnt = sal_False; // kein Platz mehr ?? 814 else 815 pMyBox = (SwTableBox*)pTmp; 816 817 } while( sal_True ); 818 819 // suche die oberste Line 820 SwTableLine* pNxtLine = pMyBox->GetUpper(); 821 while( pNxtLine->GetUpper() ) 822 pNxtLine = pNxtLine->GetUpper()->GetUpper(); 823 sal_uInt16 nPos = GetTabLines().C40_GETPOS( SwTableLine, pNxtLine ); 824 // gibt es eine naechste ?? 825 if( nPos + 1 >= GetTabLines().Count() ) 826 bDelCntnt = sal_False; // es gibt keine, alles in die letzte Box 827 else 828 { 829 // suche die naechste "Inhaltstragende Box" 830 pNxtLine = GetTabLines()[ nPos+1 ]; 831 pMyBox = pNxtLine->GetTabBoxes()[0]; 832 while( pMyBox->GetTabLines().Count() ) 833 pMyBox = pMyBox->GetTabLines()[0]->GetTabBoxes()[0]; 834 bDelCntnt = sal_True; 835 } 836 } 837 838 aFndBox.MakeFrms( pTblNd->GetTable() ); // erzeuge die Frames neu 839 return sal_True; 840 } 841 842 843 sal_Bool SwTable::InsTable( const SwTable& rCpyTbl, const SwSelBoxes& rSelBoxes, 844 SwUndoTblCpyTbl* pUndo ) 845 { 846 ASSERT( rSelBoxes.Count(), "Missing selection" ) 847 848 SetHTMLTableLayout( 0 ); // MIB 9.7.97: HTML-Layout loeschen 849 850 if( IsNewModel() || rCpyTbl.IsNewModel() ) 851 return InsNewTable( rCpyTbl, rSelBoxes, pUndo ); 852 853 ASSERT( !rCpyTbl.IsTblComplex(), "Table too complex" ) 854 855 SwDoc* pDoc = GetFrmFmt()->GetDoc(); 856 SwDoc* pCpyDoc = rCpyTbl.GetFrmFmt()->GetDoc(); 857 858 SwTblNumFmtMerge aTNFM( *pCpyDoc, *pDoc ); 859 860 SwTableBox *pTmpBox, *pSttBox = (SwTableBox*)rSelBoxes[0]; 861 862 sal_uInt16 nLn, nBx; 863 _FndLine *pFLine, *pInsFLine = 0; 864 _FndBox aFndBox( 0, 0 ); 865 // suche alle Boxen / Lines 866 { 867 _FndPara aPara( rSelBoxes, &aFndBox ); 868 ((SwTableLines&)GetTabLines()).ForEach( &_FndLineCopyCol, &aPara ); 869 } 870 871 // JP 06.09.96: Sonderfall - eine Box in der Tabelle -> in alle 872 // selektierten Boxen kopieren! 873 if( 1 != rCpyTbl.GetTabSortBoxes().Count() ) 874 { 875 SwTableLine* pSttLine = pSttBox->GetUpper(); 876 sal_uInt16 nSttBox = pSttLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSttBox ); 877 sal_uInt16 nSttLine = GetTabLines().C40_GETPOS( SwTableLine, pSttLine ); 878 _FndBox* pFndBox; 879 880 sal_uInt16 nFndCnt = aFndBox.GetLines().Count(); 881 if( !nFndCnt ) 882 return sal_False; 883 884 // teste ob genug Platz fuer die einzelnen Lines und Boxen ist: 885 sal_uInt16 nTstLns = 0; 886 pFLine = aFndBox.GetLines()[ 0 ]; 887 pSttLine = pFLine->GetLine(); 888 nSttLine = GetTabLines().C40_GETPOS( SwTableLine, pSttLine ); 889 // sind ueberhaupt soviele Zeilen vorhanden 890 if( 1 == nFndCnt ) 891 { 892 // in der Tabelle noch genug Platz ?? 893 if( (GetTabLines().Count() - nSttLine ) < 894 rCpyTbl.GetTabLines().Count() ) 895 { 896 // sollte nicht mehr soviele Lines vorhanden sein, dann 897 // teste, ob man durch einfuegen neuer zum Ziel kommt. Aber 898 // nur wenn die SSelection eine Box umfasst !! 899 if( 1 < rSelBoxes.Count() ) 900 return sal_False; 901 902 sal_uInt16 nNewLns = rCpyTbl.GetTabLines().Count() - 903 (GetTabLines().Count() - nSttLine ); 904 905 // Dann teste mal ob die Anzahl der Boxen fuer die Lines reicht 906 SwTableLine* pLastLn = GetTabLines()[ GetTabLines().Count()-1 ]; 907 908 pSttBox = pFLine->GetBoxes()[0]->GetBox(); 909 nSttBox = pFLine->GetLine()->GetTabBoxes().C40_GETPOS( SwTableBox, pSttBox ); 910 for( sal_uInt16 n = rCpyTbl.GetTabLines().Count() - nNewLns; 911 n < rCpyTbl.GetTabLines().Count(); ++n ) 912 { 913 SwTableLine* pCpyLn = rCpyTbl.GetTabLines()[ n ]; 914 915 if( pLastLn->GetTabBoxes().Count() < nSttBox || 916 ( pLastLn->GetTabBoxes().Count() - nSttBox ) < 917 pCpyLn->GetTabBoxes().Count() ) 918 return sal_False; 919 920 // Test auf Verschachtelungen 921 for( nBx = 0; nBx < pCpyLn->GetTabBoxes().Count(); ++nBx ) 922 if( !( pTmpBox = pLastLn->GetTabBoxes()[ nSttBox + nBx ]) 923 ->GetSttNd() ) 924 return sal_False; 925 } 926 // es ist also Platz fuer das zu kopierende vorhanden, also 927 // fuege entsprechend neue Zeilen ein. 928 SwTableBox* pInsBox = pLastLn->GetTabBoxes()[ nSttBox ]; 929 ASSERT( pInsBox && pInsBox->GetSttNd(), 930 "kein CntntBox oder steht nicht in dieser Tabelle" ); 931 SwSelBoxes aBoxes; 932 933 if( pUndo 934 ? !pUndo->InsertRow( *this, SelLineFromBox( pInsBox, 935 aBoxes, sal_True ), nNewLns ) 936 : !InsertRow( pDoc, SelLineFromBox( pInsBox, 937 aBoxes, sal_True ), nNewLns, sal_True ) ) 938 return sal_False; 939 } 940 941 nTstLns = rCpyTbl.GetTabLines().Count(); // soviele Kopieren 942 } 943 else if( 0 == (nFndCnt % rCpyTbl.GetTabLines().Count()) ) 944 nTstLns = nFndCnt; 945 else 946 return sal_False; // kein Platz fuer die Zeilen 947 948 for( nLn = 0; nLn < nTstLns; ++nLn ) 949 { 950 // Zeilen sind genug vorhanden, dann ueberpruefe die Boxen 951 // je Zeile 952 pFLine = aFndBox.GetLines()[ nLn % nFndCnt ]; 953 SwTableLine* pLine = pFLine->GetLine(); 954 pSttBox = pFLine->GetBoxes()[0]->GetBox(); 955 nSttBox = pLine->GetTabBoxes().C40_GETPOS( SwTableBox, pSttBox ); 956 if( nLn >= nFndCnt ) 957 { 958 // es sind im ClipBoard mehr Zeilen als selectiert wurden 959 pInsFLine = new _FndLine( GetTabLines()[ nSttLine + nLn ], 960 &aFndBox ); 961 pLine = pInsFLine->GetLine(); 962 } 963 SwTableLine* pCpyLn = rCpyTbl.GetTabLines()[ nLn % 964 rCpyTbl.GetTabLines().Count() ]; 965 966 // zu wenig Zeilen selektiert ? 967 if( pInsFLine ) 968 { 969 // eine neue Zeile wird in die FndBox eingefuegt, 970 if( pLine->GetTabBoxes().Count() < nSttBox || 971 ( pLine->GetTabBoxes().Count() - nSttBox ) < 972 pFLine->GetBoxes().Count() ) 973 return sal_False; 974 975 // Test auf Verschachtelungen 976 for( nBx = 0; nBx < pFLine->GetBoxes().Count(); ++nBx ) 977 { 978 if( !( pTmpBox = pLine->GetTabBoxes()[ nSttBox + nBx ]) 979 ->GetSttNd() ) 980 return sal_False; 981 // wenn Ok, fuege die Box in die FndLine zu 982 pFndBox = new _FndBox( pTmpBox, pInsFLine ); 983 pInsFLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, nBx ); 984 } 985 aFndBox.GetLines().C40_INSERT( _FndLine, pInsFLine, nLn ); 986 } 987 else if( pFLine->GetBoxes().Count() == 1 ) 988 { 989 if( pLine->GetTabBoxes().Count() < nSttBox || 990 ( pLine->GetTabBoxes().Count() - nSttBox ) < 991 pCpyLn->GetTabBoxes().Count() ) 992 return sal_False; 993 994 // Test auf Verschachtelungen 995 for( nBx = 0; nBx < pCpyLn->GetTabBoxes().Count(); ++nBx ) 996 { 997 if( !( pTmpBox = pLine->GetTabBoxes()[ nSttBox + nBx ]) 998 ->GetSttNd() ) 999 return sal_False; 1000 // wenn Ok, fuege die Box in die FndLine zu 1001 if( nBx == pFLine->GetBoxes().Count() ) 1002 { 1003 pFndBox = new _FndBox( pTmpBox, pFLine ); 1004 pFLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, nBx ); 1005 } 1006 } 1007 } 1008 else 1009 { 1010 // ueberpruefe die selektierten Boxen mit denen im Clipboard 1011 // (n-Fach) 1012 if( 0 != ( pFLine->GetBoxes().Count() % 1013 pCpyLn->GetTabBoxes().Count() )) 1014 return sal_False; 1015 1016 // Test auf Verschachtelungen 1017 for( nBx = 0; nBx < pFLine->GetBoxes().Count(); ++nBx ) 1018 if( !pFLine->GetBoxes()[ nBx ]->GetBox()->GetSttNd() ) 1019 return sal_False; 1020 } 1021 } 1022 1023 if( !aFndBox.GetLines().Count() ) 1024 return sal_False; 1025 } 1026 1027 { 1028 // Tabellen-Formeln in die relative Darstellung umwandeln 1029 SwTableFmlUpdate aMsgHnt( &rCpyTbl ); 1030 aMsgHnt.eFlags = TBL_RELBOXNAME; 1031 pCpyDoc->UpdateTblFlds( &aMsgHnt ); 1032 } 1033 1034 // loesche die Frames 1035 aFndBox.SetTableLines( *this ); 1036 aFndBox.DelFrms( *this ); 1037 1038 if( 1 == rCpyTbl.GetTabSortBoxes().Count() ) 1039 { 1040 SwTableBox *pTmpBx = rCpyTbl.GetTabSortBoxes()[0]; 1041 for( sal_uInt16 n = 0; n < rSelBoxes.Count(); ++n ) 1042 lcl_CpyBox( rCpyTbl, pTmpBx, *this, 1043 (SwTableBox*)rSelBoxes[n], sal_True, pUndo ); 1044 } 1045 else 1046 for( nLn = 0; nLn < aFndBox.GetLines().Count(); ++nLn ) 1047 { 1048 pFLine = aFndBox.GetLines()[ nLn ]; 1049 SwTableLine* pCpyLn = rCpyTbl.GetTabLines()[ 1050 nLn % rCpyTbl.GetTabLines().Count() ]; 1051 for( nBx = 0; nBx < pFLine->GetBoxes().Count(); ++nBx ) 1052 { 1053 // Kopiere in pMyBox die pCpyBox 1054 lcl_CpyBox( rCpyTbl, pCpyLn->GetTabBoxes()[ 1055 nBx % pCpyLn->GetTabBoxes().Count() ], 1056 *this, pFLine->GetBoxes()[ nBx ]->GetBox(), sal_True, pUndo ); 1057 } 1058 } 1059 1060 aFndBox.MakeFrms( *this ); 1061 return sal_True; 1062 } 1063 1064 1065 1066 sal_Bool _FndCntntBox( const SwTableBox*& rpBox, void* pPara ) 1067 { 1068 SwTableBox* pBox = (SwTableBox*)rpBox; 1069 if( rpBox->GetTabLines().Count() ) 1070 pBox->GetTabLines().ForEach( &_FndCntntLine, pPara ); 1071 else 1072 ((SwSelBoxes*)pPara)->Insert( pBox ); 1073 return sal_True; 1074 } 1075 1076 1077 sal_Bool _FndCntntLine( const SwTableLine*& rpLine, void* pPara ) 1078 { 1079 ((SwTableLine*)rpLine)->GetTabBoxes().ForEach( &_FndCntntBox, pPara ); 1080 return sal_True; 1081 } 1082 1083 1084 // suche alle Inhaltstragenden-Boxen dieser Box 1085 SwSelBoxes& SwTable::SelLineFromBox( const SwTableBox* pBox, 1086 SwSelBoxes& rBoxes, sal_Bool bToTop ) const 1087 { 1088 SwTableLine* pLine = (SwTableLine*)pBox->GetUpper(); 1089 if( bToTop ) 1090 while( pLine->GetUpper() ) 1091 pLine = pLine->GetUpper()->GetUpper(); 1092 1093 // alle alten loeschen 1094 rBoxes.Remove( sal_uInt16(0), rBoxes.Count() ); 1095 pLine->GetTabBoxes().ForEach( &_FndCntntBox, &rBoxes ); 1096 return rBoxes; 1097 } 1098 1099 1100