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