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 #include <editeng/boxitem.hxx> 28 #include <editeng/protitem.hxx> 29 30 #include <hintids.hxx> 31 #include <fmtanchr.hxx> 32 #include <fmtfsize.hxx> 33 #include <frmatr.hxx> 34 #include <tblsel.hxx> 35 #include <crsrsh.hxx> 36 #include <doc.hxx> 37 #include <IDocumentUndoRedo.hxx> 38 #include <docary.hxx> 39 #include <pam.hxx> 40 #include <ndtxt.hxx> 41 #include <ndole.hxx> 42 #include <swtable.hxx> 43 #include <cntfrm.hxx> 44 #include <tabfrm.hxx> 45 #include <rowfrm.hxx> 46 #include <cellfrm.hxx> 47 #include <pagefrm.hxx> 48 #include <rootfrm.hxx> 49 #include <viscrs.hxx> 50 #include <swtblfmt.hxx> 51 #include <UndoTable.hxx> 52 #include <mvsave.hxx> 53 #include <sectfrm.hxx> 54 #include <frmtool.hxx> 55 #include <switerator.hxx> 56 #include <deque> 57 58 //siehe auch swtable.cxx 59 #define COLFUZZY 20L 60 61 // defines, die bestimmen, wie Tabellen Boxen gemergt werden: 62 // - 1. alle leeren Zeilen entfernen, alle Boxen werden mit Blank, 63 // alle Lines mit ParaBreak getrennt 64 // - 2. alle leeren Zeilen und alle leeren Boxen am Anfang und Ende 65 // entfernen, alle Boxen werden mit Blank, 66 // alle Lines mit ParaBreak getrennt 67 // - 3. alle leeren Boxen entfernen, alle Boxen werden mit Blank, 68 // alle Lines mit ParaBreak getrennt 69 70 #undef DEL_ONLY_EMPTY_LINES 71 #undef DEL_EMPTY_BOXES_AT_START_AND_END 72 #define DEL_ALL_EMPTY_BOXES 73 74 75 _SV_IMPL_SORTAR_ALG( SwSelBoxes, SwTableBoxPtr ) 76 sal_Bool SwSelBoxes::Seek_Entry( const SwTableBoxPtr rSrch, sal_uInt16* pFndPos ) const 77 { 78 sal_uLong nIdx = rSrch->GetSttIdx(); 79 80 sal_uInt16 nO = Count(), nM, nU = 0; 81 if( nO > 0 ) 82 { 83 nO--; 84 while( nU <= nO ) 85 { 86 nM = nU + ( nO - nU ) / 2; 87 if( (*this)[ nM ]->GetSttNd() == rSrch->GetSttNd() ) 88 { 89 if( pFndPos ) 90 *pFndPos = nM; 91 return sal_True; 92 } 93 else if( (*this)[ nM ]->GetSttIdx() < nIdx ) 94 nU = nM + 1; 95 else if( nM == 0 ) 96 { 97 if( pFndPos ) 98 *pFndPos = nU; 99 return sal_False; 100 } 101 else 102 nO = nM - 1; 103 } 104 } 105 if( pFndPos ) 106 *pFndPos = nU; 107 return sal_False; 108 } 109 110 111 SV_IMPL_PTRARR( SwCellFrms, SwCellFrm* ) 112 113 struct _CmpLPt 114 { 115 Point aPos; 116 const SwTableBox* pSelBox; 117 sal_Bool bVert; 118 119 _CmpLPt( const Point& rPt, const SwTableBox* pBox, sal_Bool bVertical ); 120 121 sal_Bool operator==( const _CmpLPt& rCmp ) const 122 { return X() == rCmp.X() && Y() == rCmp.Y() ? sal_True : sal_False; } 123 124 sal_Bool operator<( const _CmpLPt& rCmp ) const 125 { 126 if ( bVert ) 127 return X() > rCmp.X() || ( X() == rCmp.X() && Y() < rCmp.Y() ) 128 ? sal_True : sal_False; 129 else 130 return Y() < rCmp.Y() || ( Y() == rCmp.Y() && X() < rCmp.X() ) 131 ? sal_True : sal_False; 132 } 133 134 long X() const { return aPos.X(); } 135 long Y() const { return aPos.Y(); } 136 }; 137 138 139 SV_DECL_VARARR_SORT( _MergePos, _CmpLPt, 0, 40 ) 140 SV_IMPL_VARARR_SORT( _MergePos, _CmpLPt ) 141 142 SV_IMPL_PTRARR( _FndBoxes, _FndBox* ) 143 SV_IMPL_PTRARR( _FndLines, _FndLine* ) 144 145 146 struct _Sort_CellFrm 147 { 148 const SwCellFrm* pFrm; 149 150 _Sort_CellFrm( const SwCellFrm& rCFrm ) 151 : pFrm( &rCFrm ) {} 152 }; 153 154 typedef std::deque< _Sort_CellFrm > _Sort_CellFrms; 155 156 SV_IMPL_PTRARR( SwChartBoxes, SwTableBoxPtr ); 157 SV_IMPL_PTRARR( SwChartLines, SwChartBoxes* ); 158 159 const SwLayoutFrm *lcl_FindCellFrm( const SwLayoutFrm *pLay ) 160 { 161 while ( pLay && !pLay->IsCellFrm() ) 162 pLay = pLay->GetUpper(); 163 return pLay; 164 } 165 166 const SwLayoutFrm *lcl_FindNextCellFrm( const SwLayoutFrm *pLay ) 167 { 168 //Dafuer sorgen, dass die Zelle auch verlassen wird (Bereiche) 169 const SwLayoutFrm *pTmp = pLay; 170 do { 171 pTmp = pTmp->GetNextLayoutLeaf(); 172 } while( pLay->IsAnLower( pTmp ) ); 173 174 while( pTmp && !pTmp->IsCellFrm() ) 175 pTmp = pTmp->GetUpper(); 176 return pTmp; 177 } 178 179 void GetTblSelCrs( const SwCrsrShell &rShell, SwSelBoxes& rBoxes ) 180 { 181 if( rBoxes.Count() ) 182 rBoxes.Remove( sal_uInt16(0), rBoxes.Count() ); 183 if( rShell.IsTableMode() && ((SwCrsrShell&)rShell).UpdateTblSelBoxes()) 184 rBoxes.Insert( &rShell.GetTableCrsr()->GetBoxes() ); 185 } 186 187 void GetTblSelCrs( const SwTableCursor& rTblCrsr, SwSelBoxes& rBoxes ) 188 { 189 if( rBoxes.Count() ) 190 rBoxes.Remove( sal_uInt16(0), rBoxes.Count() ); 191 192 if( rTblCrsr.IsChgd() || !rTblCrsr.GetBoxesCount() ) 193 { 194 SwTableCursor* pTCrsr = (SwTableCursor*)&rTblCrsr; 195 pTCrsr->GetDoc()->GetCurrentLayout()->MakeTblCrsrs( *pTCrsr ); //swmod 080218 196 } 197 198 if( rTblCrsr.GetBoxesCount() ) 199 rBoxes.Insert( &rTblCrsr.GetBoxes() ); 200 } 201 202 void GetTblSel( const SwCrsrShell& rShell, SwSelBoxes& rBoxes, 203 const SwTblSearchType eSearchType ) 204 { 205 //Start- und Endzelle besorgen und den naechsten fragen. 206 if ( !rShell.IsTableMode() ) 207 rShell.GetCrsr(); 208 209 GetTblSel( *rShell.getShellCrsr(false), rBoxes, eSearchType ); 210 } 211 212 void GetTblSel( const SwCursor& rCrsr, SwSelBoxes& rBoxes, 213 const SwTblSearchType eSearchType ) 214 { 215 //Start- und Endzelle besorgen und den naechsten fragen. 216 ASSERT( rCrsr.GetCntntNode() && rCrsr.GetCntntNode( sal_False ), 217 "Tabselection nicht auf Cnt." ); 218 219 // Zeilen-Selektion: 220 // teste ob Tabelle komplex ist. Wenn ja, dann immer uebers Layout 221 // die selektierten Boxen zusammen suchen. Andernfalls ueber die 222 // Tabellen-Struktur (fuer Makros !!) 223 const SwCntntNode* pContentNd = rCrsr.GetNode()->GetCntntNode(); 224 const SwTableNode* pTblNd = pContentNd ? pContentNd->FindTableNode() : 0; 225 if( pTblNd && pTblNd->GetTable().IsNewModel() ) 226 { 227 SwTable::SearchType eSearch; 228 switch( nsSwTblSearchType::TBLSEARCH_COL & eSearchType ) 229 { 230 case nsSwTblSearchType::TBLSEARCH_ROW: eSearch = SwTable::SEARCH_ROW; break; 231 case nsSwTblSearchType::TBLSEARCH_COL: eSearch = SwTable::SEARCH_COL; break; 232 default: eSearch = SwTable::SEARCH_NONE; break; 233 } 234 const bool bChkP = 0 != ( nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType ); 235 pTblNd->GetTable().CreateSelection( rCrsr, rBoxes, eSearch, bChkP ); 236 return; 237 } 238 if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) && 239 pTblNd && !pTblNd->GetTable().IsTblComplex() ) 240 { 241 const SwTable& rTbl = pTblNd->GetTable(); 242 const SwTableLines& rLines = rTbl.GetTabLines(); 243 244 const SwNode* pMarkNode = rCrsr.GetNode( sal_False ); 245 const sal_uLong nMarkSectionStart = pMarkNode->StartOfSectionIndex(); 246 const SwTableBox* pMarkBox = rTbl.GetTblBox( nMarkSectionStart ); 247 248 ASSERT( pMarkBox, "Point in table, mark outside?" ) 249 250 const SwTableLine* pLine = pMarkBox ? pMarkBox->GetUpper() : 0; 251 sal_uInt16 nSttPos = rLines.GetPos( pLine ); 252 ASSERT( USHRT_MAX != nSttPos, "Wo ist meine Zeile in der Tabelle?" ); 253 pLine = rTbl.GetTblBox( rCrsr.GetNode( sal_True )->StartOfSectionIndex() )->GetUpper(); 254 sal_uInt16 nEndPos = rLines.GetPos( pLine ); 255 ASSERT( USHRT_MAX != nEndPos, "Wo ist meine Zeile in der Tabelle?" ); 256 // pb: #i20193# if tableintable then nSttPos == nEndPos == USHRT_MAX 257 if ( nSttPos != USHRT_MAX && nEndPos != USHRT_MAX ) 258 { 259 if( nEndPos < nSttPos ) // vertauschen 260 { 261 sal_uInt16 nTmp = nSttPos; nSttPos = nEndPos; nEndPos = nTmp; 262 } 263 264 int bChkProtected = nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType; 265 for( ; nSttPos <= nEndPos; ++nSttPos ) 266 { 267 pLine = rLines[ nSttPos ]; 268 for( sal_uInt16 n = pLine->GetTabBoxes().Count(); n ; ) 269 { 270 SwTableBox* pBox = pLine->GetTabBoxes()[ --n ]; 271 // Zellenschutzt beachten ?? 272 if( !bChkProtected || 273 !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) 274 rBoxes.Insert( pBox ); 275 } 276 } 277 } 278 } 279 else 280 { 281 Point aPtPos, aMkPos; 282 const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr); 283 if( pShCrsr ) 284 { 285 aPtPos = pShCrsr->GetPtPos(); 286 aMkPos = pShCrsr->GetMkPos(); 287 } 288 const SwCntntNode *pCntNd = rCrsr.GetCntntNode(); 289 const SwLayoutFrm *pStart = pCntNd ? 290 pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), &aPtPos )->GetUpper() : 0; 291 pCntNd = rCrsr.GetCntntNode(sal_False); 292 const SwLayoutFrm *pEnd = pCntNd ? 293 pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), &aMkPos )->GetUpper() : 0; 294 if( pStart && pEnd ) 295 GetTblSel( pStart, pEnd, rBoxes, 0, eSearchType ); 296 } 297 } 298 299 void GetTblSel( const SwLayoutFrm* pStart, const SwLayoutFrm* pEnd, 300 SwSelBoxes& rBoxes, SwCellFrms* pCells, 301 const SwTblSearchType eSearchType ) 302 { 303 // #112697# Robust: 304 const SwTabFrm* pStartTab = pStart->FindTabFrm(); 305 if ( !pStartTab ) 306 { 307 ASSERT( false, "GetTblSel without start table" ) 308 return; 309 } 310 311 int bChkProtected = nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType; 312 313 sal_Bool bTblIsValid; 314 // --> FME 2006-01-25 #i55421# Reduced value 10 315 int nLoopMax = 10; //JP 28.06.99: max 100 loops - Bug 67292 316 // <-- 317 sal_uInt16 i; 318 319 do { 320 bTblIsValid = sal_True; 321 322 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. 323 SwSelUnions aUnions; 324 ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType ); 325 326 Point aCurrentTopLeft( LONG_MAX, LONG_MAX ); 327 Point aCurrentTopRight( 0, LONG_MAX ); 328 Point aCurrentBottomLeft( LONG_MAX, 0 ); 329 Point aCurrentBottomRight( 0, 0 ); 330 const SwCellFrm* pCurrentTopLeftFrm = 0; 331 const SwCellFrm* pCurrentTopRightFrm = 0; 332 const SwCellFrm* pCurrentBottomLeftFrm = 0; 333 const SwCellFrm* pCurrentBottomRightFrm = 0; 334 335 //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen. 336 for( i = 0; i < aUnions.Count() && bTblIsValid; ++i ) 337 { 338 SwSelUnion *pUnion = aUnions[i]; 339 const SwTabFrm *pTable = pUnion->GetTable(); 340 if( !pTable->IsValid() && nLoopMax ) 341 { 342 bTblIsValid = sal_False; 343 break; 344 } 345 346 // Skip any repeated headlines in the follow: 347 const SwLayoutFrm* pRow = pTable->IsFollow() ? 348 pTable->GetFirstNonHeadlineRow() : 349 (const SwLayoutFrm*)pTable->Lower(); 350 351 while( pRow && bTblIsValid ) 352 { 353 if( !pRow->IsValid() && nLoopMax ) 354 { 355 bTblIsValid = sal_False; 356 break; 357 } 358 359 if ( pRow->Frm().IsOver( pUnion->GetUnion() ) ) 360 { 361 const SwLayoutFrm *pCell = pRow->FirstCell(); 362 363 while( bTblIsValid && pCell && pRow->IsAnLower( pCell ) ) 364 { 365 if( !pCell->IsValid() && nLoopMax ) 366 { 367 bTblIsValid = sal_False; 368 break; 369 } 370 371 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); 372 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) 373 { 374 SwTableBox* pBox = (SwTableBox*) 375 ((SwCellFrm*)pCell)->GetTabBox(); 376 // Zellenschutzt beachten ?? 377 if( !bChkProtected || 378 !pBox->GetFrmFmt()->GetProtect().IsCntntProtected() ) 379 rBoxes.Insert( pBox ); 380 381 if ( pCells ) 382 { 383 const Point aTopLeft( pCell->Frm().TopLeft() ); 384 const Point aTopRight( pCell->Frm().TopRight() ); 385 const Point aBottomLeft( pCell->Frm().BottomLeft() ); 386 const Point aBottomRight( pCell->Frm().BottomRight() ); 387 388 if ( aTopLeft.Y() < aCurrentTopLeft.Y() || 389 ( aTopLeft.Y() == aCurrentTopLeft.Y() && 390 aTopLeft.X() < aCurrentTopLeft.X() ) ) 391 { 392 aCurrentTopLeft = aTopLeft; 393 pCurrentTopLeftFrm = static_cast<const SwCellFrm*>( pCell ); 394 } 395 396 if ( aTopRight.Y() < aCurrentTopRight.Y() || 397 ( aTopRight.Y() == aCurrentTopRight.Y() && 398 aTopRight.X() > aCurrentTopRight.X() ) ) 399 { 400 aCurrentTopRight = aTopRight; 401 pCurrentTopRightFrm = static_cast<const SwCellFrm*>( pCell ); 402 } 403 404 if ( aBottomLeft.Y() > aCurrentBottomLeft.Y() || 405 ( aBottomLeft.Y() == aCurrentBottomLeft.Y() && 406 aBottomLeft.X() < aCurrentBottomLeft.X() ) ) 407 { 408 aCurrentBottomLeft = aBottomLeft; 409 pCurrentBottomLeftFrm = static_cast<const SwCellFrm*>( pCell ); 410 } 411 412 if ( aBottomRight.Y() > aCurrentBottomRight.Y() || 413 ( aBottomRight.Y() == aCurrentBottomRight.Y() && 414 aBottomRight.X() > aCurrentBottomRight.X() ) ) 415 { 416 aCurrentBottomRight = aBottomRight; 417 pCurrentBottomRightFrm = static_cast<const SwCellFrm*>( pCell ); 418 } 419 420 } 421 } 422 if ( pCell->GetNext() ) 423 { 424 pCell = (const SwLayoutFrm*)pCell->GetNext(); 425 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) 426 pCell = pCell->FirstCell(); 427 } 428 else 429 pCell = ::lcl_FindNextCellFrm( pCell ); 430 } 431 } 432 pRow = (const SwLayoutFrm*)pRow->GetNext(); 433 } 434 } 435 436 if ( pCells ) 437 { 438 pCells->Remove( 0, pCells->Count() ); 439 pCells->Insert( pCurrentTopLeftFrm, 0 ); 440 pCells->Insert( pCurrentTopRightFrm, 1 ); 441 pCells->Insert( pCurrentBottomLeftFrm, 2 ); 442 pCells->Insert( pCurrentBottomRightFrm, 3 ); 443 } 444 445 if( bTblIsValid ) 446 break; 447 448 SwDeletionChecker aDelCheck( pStart ); 449 450 // ansonsten das Layout der Tabelle kurz "kalkulieren" lassen 451 // und nochmals neu aufsetzen 452 SwTabFrm *pTable = aUnions[0]->GetTable(); 453 while( pTable ) 454 { 455 if( pTable->IsValid() ) 456 pTable->InvalidatePos(); 457 pTable->SetONECalcLowers(); 458 pTable->Calc(); 459 pTable->SetCompletePaint(); 460 if( 0 == (pTable = pTable->GetFollow()) ) 461 break; 462 } 463 464 // --> FME 2005-10-13 #125337# Make code robust, check if pStart has 465 // been deleted due to the formatting of the table: 466 if ( aDelCheck.HasBeenDeleted() ) 467 { 468 ASSERT( false, "Current box has been deleted during GetTblSel()" ) 469 break; 470 } 471 // <-- 472 473 i = 0; 474 rBoxes.Remove( i, rBoxes.Count() ); 475 --nLoopMax; 476 477 } while( sal_True ); 478 ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" ); 479 } 480 481 482 483 sal_Bool ChkChartSel( const SwNode& rSttNd, const SwNode& rEndNd, 484 SwChartLines* pGetCLines ) 485 { 486 const SwTableNode* pTNd = rSttNd.FindTableNode(); 487 if( !pTNd ) 488 return sal_False; 489 490 Point aNullPos; 491 SwNodeIndex aIdx( rSttNd ); 492 const SwCntntNode* pCNd = aIdx.GetNode().GetCntntNode(); 493 if( !pCNd ) 494 pCNd = aIdx.GetNodes().GoNextSection( &aIdx, sal_False, sal_False ); 495 496 // #109394# if table is invisible, return 497 // (layout needed for forming table selection further down, so we can't 498 // continue with invisible tables) 499 // OD 07.11.2003 #i22135# - Also the content of the table could be 500 // invisible - e.g. in a hidden section 501 // Robust: check, if content was found (e.g. empty table cells) 502 if ( !pCNd || pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() ) == NULL ) 503 return sal_False; 504 505 const SwLayoutFrm *pStart = pCNd ? pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aNullPos )->GetUpper() : 0; 506 ASSERT( pStart, "ohne Frame geht gar nichts" ); 507 508 aIdx = rEndNd; 509 pCNd = aIdx.GetNode().GetCntntNode(); 510 if( !pCNd ) 511 pCNd = aIdx.GetNodes().GoNextSection( &aIdx, sal_False, sal_False ); 512 513 // OD 07.11.2003 #i22135# - Robust: check, if content was found and if it's visible 514 if ( !pCNd || pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout() ) == NULL ) 515 { 516 return sal_False; 517 } 518 519 const SwLayoutFrm *pEnd = pCNd ? pCNd->getLayoutFrm( pCNd->GetDoc()->GetCurrentLayout(), &aNullPos )->GetUpper() : 0; 520 ASSERT( pEnd, "ohne Frame geht gar nichts" ); 521 522 523 sal_Bool bTblIsValid, bValidChartSel; 524 // --> FME 2006-01-25 #i55421# Reduced value 10 525 int nLoopMax = 10; //JP 28.06.99: max 100 loops - Bug 67292 526 // <-- 527 sal_uInt16 i = 0; 528 529 do { 530 bTblIsValid = sal_True; 531 bValidChartSel = sal_True; 532 533 sal_uInt16 nRowCells = USHRT_MAX; 534 535 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. 536 SwSelUnions aUnions; 537 ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT ); 538 539 //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen. 540 for( i = 0; i < aUnions.Count() && bTblIsValid && 541 bValidChartSel; ++i ) 542 { 543 SwSelUnion *pUnion = aUnions[i]; 544 const SwTabFrm *pTable = pUnion->GetTable(); 545 546 SWRECTFN( pTable ) 547 sal_Bool bRTL = pTable->IsRightToLeft(); 548 549 if( !pTable->IsValid() && nLoopMax ) 550 { 551 bTblIsValid = sal_False; 552 break; 553 } 554 555 _Sort_CellFrms aCellFrms; 556 557 // Skip any repeated headlines in the follow: 558 const SwLayoutFrm* pRow = pTable->IsFollow() ? 559 pTable->GetFirstNonHeadlineRow() : 560 (const SwLayoutFrm*)pTable->Lower(); 561 562 while( pRow && bTblIsValid && bValidChartSel ) 563 { 564 if( !pRow->IsValid() && nLoopMax ) 565 { 566 bTblIsValid = sal_False; 567 break; 568 } 569 570 if( pRow->Frm().IsOver( pUnion->GetUnion() ) ) 571 { 572 const SwLayoutFrm *pCell = pRow->FirstCell(); 573 574 while( bValidChartSel && bTblIsValid && pCell && 575 pRow->IsAnLower( pCell ) ) 576 { 577 if( !pCell->IsValid() && nLoopMax ) 578 { 579 bTblIsValid = sal_False; 580 break; 581 } 582 583 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); 584 const SwRect& rUnion = pUnion->GetUnion(), 585 & rFrmRect = pCell->Frm(); 586 587 const long nUnionRight = rUnion.Right(); 588 const long nUnionBottom = rUnion.Bottom(); 589 const long nFrmRight = rFrmRect.Right(); 590 const long nFrmBottom = rFrmRect.Bottom(); 591 592 // liegt das FrmRect ausserhalb der Union, kann es 593 // ignoriert werden. 594 595 const long nXFuzzy = bVert ? 0 : 20; 596 const long nYFuzzy = bVert ? 20 : 0; 597 598 if( !( rUnion.Top() + nYFuzzy > nFrmBottom || 599 nUnionBottom < rFrmRect.Top() + nYFuzzy || 600 rUnion.Left() + nXFuzzy > nFrmRight || 601 nUnionRight < rFrmRect.Left() + nXFuzzy )) 602 { 603 // ok, rUnion is _not_ completely outside of rFrmRect 604 605 // wenn es aber nicht komplett in der Union liegt, 606 // dann ist es fuers Chart eine ungueltige 607 // Selektion. 608 if( rUnion.Left() <= rFrmRect.Left() + nXFuzzy && 609 rFrmRect.Left() <= nUnionRight && 610 rUnion.Left() <= nFrmRight && 611 nFrmRight <= nUnionRight + nXFuzzy && 612 rUnion.Top() <= rFrmRect.Top() + nYFuzzy && 613 rFrmRect.Top() <= nUnionBottom && 614 rUnion.Top() <= nFrmBottom && 615 nFrmBottom <= nUnionBottom+ nYFuzzy ) 616 617 aCellFrms.push_back( 618 _Sort_CellFrm( *(SwCellFrm*)pCell) ); 619 else 620 { 621 bValidChartSel = sal_False; 622 break; 623 } 624 } 625 if ( pCell->GetNext() ) 626 { 627 pCell = (const SwLayoutFrm*)pCell->GetNext(); 628 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) 629 pCell = pCell->FirstCell(); 630 } 631 else 632 pCell = ::lcl_FindNextCellFrm( pCell ); 633 } 634 } 635 pRow = (const SwLayoutFrm*)pRow->GetNext(); 636 } 637 638 if( !bValidChartSel ) 639 break; 640 641 // alle Zellen der (Teil-)Tabelle zusammen. Dann teste mal ob 642 // all huebsch nebeneinander liegen. 643 size_t n; 644 sal_uInt16 nCellCnt = 0; 645 long nYPos = LONG_MAX; 646 long nXPos = 0; 647 long nHeight = 0; 648 649 for( n = 0 ; n < aCellFrms.size(); ++n ) 650 { 651 const _Sort_CellFrm& rCF = aCellFrms[ n ]; 652 if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos ) 653 { 654 // neue Zeile 655 if( n ) 656 { 657 if( USHRT_MAX == nRowCells ) // 1. Zeilenwechsel 658 nRowCells = nCellCnt; 659 else if( nRowCells != nCellCnt ) 660 { 661 bValidChartSel = sal_False; 662 break; 663 } 664 } 665 nCellCnt = 1; 666 nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)(); 667 nHeight = (rCF.pFrm->Frm().*fnRect->fnGetHeight)(); 668 669 nXPos = bRTL ? 670 (rCF.pFrm->Frm().*fnRect->fnGetLeft)() : 671 (rCF.pFrm->Frm().*fnRect->fnGetRight)(); 672 } 673 else if( nXPos == ( bRTL ? 674 (rCF.pFrm->Frm().*fnRect->fnGetRight)() : 675 (rCF.pFrm->Frm().*fnRect->fnGetLeft)() ) && 676 nHeight == (rCF.pFrm->Frm().*fnRect->fnGetHeight)() ) 677 { 678 nXPos += ( bRTL ? (-1) : 1 ) * 679 (rCF.pFrm->Frm().*fnRect->fnGetWidth)(); 680 ++nCellCnt; 681 } 682 else 683 { 684 bValidChartSel = sal_False; 685 break; 686 } 687 } 688 if( bValidChartSel ) 689 { 690 if( USHRT_MAX == nRowCells ) 691 nRowCells = nCellCnt; 692 else if( nRowCells != nCellCnt ) 693 bValidChartSel = sal_False; 694 } 695 696 if( bValidChartSel && pGetCLines ) 697 { 698 nYPos = LONG_MAX; 699 SwChartBoxes* pBoxes = 0; 700 for( n = 0; n < aCellFrms.size(); ++n ) 701 { 702 const _Sort_CellFrm& rCF = aCellFrms[ n ]; 703 if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos ) 704 { 705 pBoxes = new SwChartBoxes( 255 < nRowCells 706 ? 255 : (sal_uInt8)nRowCells); 707 pGetCLines->C40_INSERT( SwChartBoxes, pBoxes, pGetCLines->Count() ); 708 nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)(); 709 } 710 SwTableBoxPtr pBox = (SwTableBox*)rCF.pFrm->GetTabBox(); 711 pBoxes->Insert( pBox, pBoxes->Count() ); 712 } 713 } 714 } 715 716 if( bTblIsValid ) 717 break; 718 719 // ansonsten das Layout der Tabelle kurz "kalkulieren" lassen 720 // und nochmals neu aufsetzen 721 SwTabFrm *pTable = aUnions[0]->GetTable(); 722 for( i = 0; i < aUnions.Count(); ++i ) 723 { 724 if( pTable->IsValid() ) 725 pTable->InvalidatePos(); 726 pTable->SetONECalcLowers(); 727 pTable->Calc(); 728 pTable->SetCompletePaint(); 729 if( 0 == (pTable = pTable->GetFollow()) ) 730 break; 731 } 732 --nLoopMax; 733 if( pGetCLines ) 734 pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() ); 735 } while( sal_True ); 736 737 ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" ); 738 739 if( !bValidChartSel && pGetCLines ) 740 pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() ); 741 742 return bValidChartSel; 743 } 744 745 746 sal_Bool IsFrmInTblSel( const SwRect& rUnion, const SwFrm* pCell ) 747 { 748 ASSERT( pCell->IsCellFrm(), "Frame ohne Gazelle" ); 749 750 if( pCell->FindTabFrm()->IsVertical() ) 751 return ( rUnion.Right() >= pCell->Frm().Right() && 752 rUnion.Left() <= pCell->Frm().Left() && 753 (( rUnion.Top() <= pCell->Frm().Top()+20 && 754 rUnion.Bottom() > pCell->Frm().Top() ) || 755 ( rUnion.Top() >= pCell->Frm().Top() && 756 rUnion.Bottom() < pCell->Frm().Bottom() )) ? sal_True : sal_False ); 757 758 return ( 759 rUnion.Top() <= pCell->Frm().Top() && 760 rUnion.Bottom() >= pCell->Frm().Bottom() && 761 762 (( rUnion.Left() <= pCell->Frm().Left()+20 && 763 rUnion.Right() > pCell->Frm().Left() ) || 764 765 ( rUnion.Left() >= pCell->Frm().Left() && 766 rUnion.Right() < pCell->Frm().Right() )) ? sal_True : sal_False ); 767 } 768 769 sal_Bool GetAutoSumSel( const SwCrsrShell& rShell, SwCellFrms& rBoxes ) 770 { 771 SwShellCrsr* pCrsr = rShell.pCurCrsr; 772 if ( rShell.IsTableMode() ) 773 pCrsr = rShell.pTblCrsr; 774 775 const SwLayoutFrm *pStart = pCrsr->GetCntntNode()->getLayoutFrm( rShell.GetLayout(), 776 &pCrsr->GetPtPos() )->GetUpper(), 777 *pEnd = pCrsr->GetCntntNode(sal_False)->getLayoutFrm( rShell.GetLayout(), 778 &pCrsr->GetMkPos() )->GetUpper(); 779 780 const SwLayoutFrm* pSttCell = pStart; 781 while( pSttCell && !pSttCell->IsCellFrm() ) 782 pSttCell = pSttCell->GetUpper(); 783 784 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. 785 SwSelUnions aUnions; 786 787 // default erstmal nach oben testen, dann nach links 788 ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_COL ); 789 790 sal_Bool bTstRow = sal_True, bFound = sal_False; 791 sal_uInt16 i; 792 793 // 1. teste ob die darueber liegende Box Value/Formel enhaelt: 794 for( i = 0; i < aUnions.Count(); ++i ) 795 { 796 SwSelUnion *pUnion = aUnions[i]; 797 const SwTabFrm *pTable = pUnion->GetTable(); 798 799 // Skip any repeated headlines in the follow: 800 const SwLayoutFrm* pRow = pTable->IsFollow() ? 801 pTable->GetFirstNonHeadlineRow() : 802 (const SwLayoutFrm*)pTable->Lower(); 803 804 while( pRow ) 805 { 806 if( pRow->Frm().IsOver( pUnion->GetUnion() ) ) 807 { 808 const SwCellFrm* pUpperCell = 0; 809 const SwLayoutFrm *pCell = pRow->FirstCell(); 810 811 while( pCell && pRow->IsAnLower( pCell ) ) 812 { 813 if( pCell == pSttCell ) 814 { 815 sal_uInt16 nWhichId = 0; 816 for( sal_uInt16 n = rBoxes.Count(); n; ) 817 if( USHRT_MAX != ( nWhichId = rBoxes[ --n ] 818 ->GetTabBox()->IsFormulaOrValueBox() )) 819 break; 820 821 // alle Boxen zusammen, nicht mehr die Zeile 822 // pruefen, wenn eine Formel oder Value gefunden wurde 823 bTstRow = 0 == nWhichId || USHRT_MAX == nWhichId; 824 bFound = sal_True; 825 break; 826 } 827 828 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); 829 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) 830 pUpperCell = (SwCellFrm*)pCell; 831 832 if( pCell->GetNext() ) 833 { 834 pCell = (const SwLayoutFrm*)pCell->GetNext(); 835 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) 836 pCell = pCell->FirstCell(); 837 } 838 else 839 pCell = ::lcl_FindNextCellFrm( pCell ); 840 } 841 842 if( pUpperCell ) 843 rBoxes.Insert( pUpperCell, rBoxes.Count() ); 844 } 845 if( bFound ) 846 { 847 i = aUnions.Count(); 848 break; 849 } 850 pRow = (const SwLayoutFrm*)pRow->GetNext(); 851 } 852 } 853 854 855 // 2. teste ob die links liegende Box Value/Formel enhaelt: 856 if( bTstRow ) 857 { 858 bFound = sal_False; 859 860 rBoxes.Remove( 0, rBoxes.Count() ); 861 aUnions.DeleteAndDestroy( 0, aUnions.Count() ); 862 ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_ROW ); 863 864 for( i = 0; i < aUnions.Count(); ++i ) 865 { 866 SwSelUnion *pUnion = aUnions[i]; 867 const SwTabFrm *pTable = pUnion->GetTable(); 868 869 // Skip any repeated headlines in the follow: 870 const SwLayoutFrm* pRow = pTable->IsFollow() ? 871 pTable->GetFirstNonHeadlineRow() : 872 (const SwLayoutFrm*)pTable->Lower(); 873 874 while( pRow ) 875 { 876 if( pRow->Frm().IsOver( pUnion->GetUnion() ) ) 877 { 878 const SwLayoutFrm *pCell = pRow->FirstCell(); 879 880 while( pCell && pRow->IsAnLower( pCell ) ) 881 { 882 if( pCell == pSttCell ) 883 { 884 sal_uInt16 nWhichId = 0; 885 for( sal_uInt16 n = rBoxes.Count(); n; ) 886 if( USHRT_MAX != ( nWhichId = rBoxes[ --n ] 887 ->GetTabBox()->IsFormulaOrValueBox() )) 888 break; 889 890 // alle Boxen zusammen, nicht mehr die Zeile 891 // pruefen, wenn eine Formel oder Value gefunden wurde 892 bFound = 0 != nWhichId && USHRT_MAX != nWhichId; 893 bTstRow = sal_False; 894 break; 895 } 896 897 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); 898 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) 899 { 900 const SwCellFrm* pC = (SwCellFrm*)pCell; 901 rBoxes.Insert( pC, rBoxes.Count() ); 902 } 903 if( pCell->GetNext() ) 904 { 905 pCell = (const SwLayoutFrm*)pCell->GetNext(); 906 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) 907 pCell = pCell->FirstCell(); 908 } 909 else 910 pCell = ::lcl_FindNextCellFrm( pCell ); 911 } 912 } 913 if( !bTstRow ) 914 { 915 i = aUnions.Count(); 916 break; 917 } 918 919 pRow = (const SwLayoutFrm*)pRow->GetNext(); 920 } 921 } 922 } 923 924 return bFound; 925 } 926 927 sal_Bool HasProtectedCells( const SwSelBoxes& rBoxes ) 928 { 929 sal_Bool bRet = sal_False; 930 for( sal_uInt16 n = 0, nCnt = rBoxes.Count(); n < nCnt; ++n ) 931 if( rBoxes[ n ]->GetFrmFmt()->GetProtect().IsCntntProtected() ) 932 { 933 bRet = sal_True; 934 break; 935 } 936 return bRet; 937 } 938 939 940 _CmpLPt::_CmpLPt( const Point& rPt, const SwTableBox* pBox, sal_Bool bVertical ) 941 : aPos( rPt ), pSelBox( pBox ), bVert( bVertical ) 942 {} 943 944 void lcl_InsTblBox( SwTableNode* pTblNd, SwDoc* pDoc, SwTableBox* pBox, 945 sal_uInt16 nInsPos, sal_uInt16 nCnt = 1 ) 946 { 947 ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" ); 948 SwCntntNode* pCNd = pDoc->GetNodes()[ pBox->GetSttIdx() + 1 ] 949 ->GetCntntNode(); 950 if( pCNd && pCNd->IsTxtNode() ) 951 pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(), 952 (SwTableBoxFmt*)pBox->GetFrmFmt(), 953 ((SwTxtNode*)pCNd)->GetTxtColl(), 954 pCNd->GetpSwAttrSet(), 955 nInsPos, nCnt ); 956 else 957 pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(), 958 (SwTableBoxFmt*)pBox->GetFrmFmt(), 959 (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0, 960 nInsPos, nCnt ); 961 } 962 963 sal_Bool IsEmptyBox( const SwTableBox& rBox, SwPaM& rPam ) 964 { 965 rPam.GetPoint()->nNode = *rBox.GetSttNd()->EndOfSectionNode(); 966 rPam.Move( fnMoveBackward, fnGoCntnt ); 967 rPam.SetMark(); 968 rPam.GetPoint()->nNode = *rBox.GetSttNd(); 969 rPam.Move( fnMoveForward, fnGoCntnt ); 970 sal_Bool bRet = *rPam.GetMark() == *rPam.GetPoint() 971 && ( rBox.GetSttNd()->GetIndex() + 1 == rPam.GetPoint()->nNode.GetIndex() ); 972 973 if( bRet ) 974 { 975 // dann teste mal auf absatzgebundenen Flys 976 const SwSpzFrmFmts& rFmts = *rPam.GetDoc()->GetSpzFrmFmts(); 977 sal_uLong nSttIdx = rPam.GetPoint()->nNode.GetIndex(), 978 nEndIdx = rBox.GetSttNd()->EndOfSectionIndex(), 979 nIdx; 980 981 for( sal_uInt16 n = 0; n < rFmts.Count(); ++n ) 982 { 983 const SwFmtAnchor& rAnchor = rFmts[n]->GetAnchor(); 984 const SwPosition* pAPos = rAnchor.GetCntntAnchor(); 985 if (pAPos && 986 ((FLY_AT_PARA == rAnchor.GetAnchorId()) || 987 (FLY_AT_CHAR == rAnchor.GetAnchorId())) && 988 nSttIdx <= ( nIdx = pAPos->nNode.GetIndex() ) && 989 nIdx < nEndIdx ) 990 { 991 bRet = sal_False; 992 break; 993 } 994 } 995 } 996 return bRet; 997 } 998 999 1000 void GetMergeSel( const SwPaM& rPam, SwSelBoxes& rBoxes, 1001 SwTableBox** ppMergeBox, SwUndoTblMerge* pUndo ) 1002 { 1003 if( rBoxes.Count() ) 1004 rBoxes.Remove( sal_uInt16(0), rBoxes.Count() ); 1005 1006 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. 1007 ASSERT( rPam.GetCntntNode() && rPam.GetCntntNode( sal_False ), 1008 "Tabselection nicht auf Cnt." ); 1009 1010 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht 1011 // richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert, 1012 // das die 1. Headline mit drin ist. 1013 // Point aPt( rShell.GetCharRect().Pos() ); 1014 Point aPt( 0, 0 ); 1015 1016 const SwCntntNode* pCntNd = rPam.GetCntntNode(); 1017 const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 1018 &aPt )->GetUpper(); 1019 pCntNd = rPam.GetCntntNode(sal_False); 1020 const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 1021 &aPt )->GetUpper(); 1022 1023 SwSelUnions aUnions; 1024 ::MakeSelUnions( aUnions, pStart, pEnd ); 1025 if( !aUnions.Count() ) 1026 return; 1027 1028 const SwTable *pTable = aUnions[0]->GetTable()->GetTable(); 1029 SwDoc* pDoc = (SwDoc*)pStart->GetFmt()->GetDoc(); 1030 SwTableNode* pTblNd = (SwTableNode*)pTable->GetTabSortBoxes()[ 0 ]-> 1031 GetSttNd()->FindTableNode(); 1032 1033 _MergePos aPosArr; // Sort-Array mit den Positionen der Frames 1034 long nWidth; 1035 SwTableBox* pLastBox = 0; 1036 1037 SWRECTFN( pStart->GetUpper() ) 1038 1039 for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) 1040 { 1041 const SwTabFrm *pTabFrm = aUnions[i]->GetTable(); 1042 1043 SwRect &rUnion = aUnions[i]->GetUnion(); 1044 1045 // Skip any repeated headlines in the follow: 1046 const SwLayoutFrm* pRow = pTabFrm->IsFollow() ? 1047 pTabFrm->GetFirstNonHeadlineRow() : 1048 (const SwLayoutFrm*)pTabFrm->Lower(); 1049 1050 while ( pRow ) 1051 { 1052 if ( pRow->Frm().IsOver( rUnion ) ) 1053 { 1054 const SwLayoutFrm *pCell = pRow->FirstCell(); 1055 1056 while ( pCell && pRow->IsAnLower( pCell ) ) 1057 { 1058 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); 1059 // in der vollen Breite ueberlappend ? 1060 if( rUnion.Top() <= pCell->Frm().Top() && 1061 rUnion.Bottom() >= pCell->Frm().Bottom() ) 1062 { 1063 SwTableBox* pBox =(SwTableBox*)((SwCellFrm*)pCell)->GetTabBox(); 1064 1065 // nur nach rechts ueberlappend 1066 if( ( rUnion.Left() - COLFUZZY ) <= pCell->Frm().Left() && 1067 ( rUnion.Right() - COLFUZZY ) > pCell->Frm().Left() ) 1068 { 1069 if( ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() ) 1070 { 1071 sal_uInt16 nInsPos = pBox->GetUpper()-> 1072 GetTabBoxes().C40_GETPOS( SwTableBox, pBox )+1; 1073 lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos ); 1074 pBox->ClaimFrmFmt(); 1075 SwFmtFrmSize aNew( 1076 pBox->GetFrmFmt()->GetFrmSize() ); 1077 nWidth = rUnion.Right() - pCell->Frm().Left(); 1078 nWidth = nWidth * aNew.GetWidth() / 1079 pCell->Frm().Width(); 1080 long nTmpWidth = aNew.GetWidth() - nWidth; 1081 aNew.SetWidth( nWidth ); 1082 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1083 // diese Box ist selektiert 1084 pLastBox = pBox; 1085 rBoxes.Insert( pBox ); 1086 aPosArr.Insert( 1087 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(), 1088 pBox, bVert ) ); 1089 1090 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ]; 1091 aNew.SetWidth( nTmpWidth ); 1092 pBox->ClaimFrmFmt(); 1093 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1094 1095 if( pUndo ) 1096 pUndo->AddNewBox( pBox->GetSttIdx() ); 1097 } 1098 else 1099 { 1100 // diese Box ist selektiert 1101 pLastBox = pBox; 1102 rBoxes.Insert( pBox ); 1103 #if OSL_DEBUG_LEVEL > 1 1104 Point aInsPoint( (pCell->Frm().*fnRect->fnGetPos)() ); 1105 #endif 1106 aPosArr.Insert( 1107 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(), 1108 pBox, bVert ) ); 1109 } 1110 } 1111 // oder rechts und links ueberlappend 1112 else if( ( rUnion.Left() - COLFUZZY ) >= pCell->Frm().Left() && 1113 ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() ) 1114 { 1115 sal_uInt16 nInsPos = pBox->GetUpper()->GetTabBoxes(). 1116 C40_GETPOS( SwTableBox, pBox )+1; 1117 lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 2 ); 1118 pBox->ClaimFrmFmt(); 1119 SwFmtFrmSize aNew( 1120 pBox->GetFrmFmt()->GetFrmSize() ); 1121 long nLeft = rUnion.Left() - pCell->Frm().Left(); 1122 nLeft = nLeft * aNew.GetWidth() / 1123 pCell->Frm().Width(); 1124 long nRight = pCell->Frm().Right() - rUnion.Right(); 1125 nRight = nRight * aNew.GetWidth() / 1126 pCell->Frm().Width(); 1127 nWidth = aNew.GetWidth() - nLeft - nRight; 1128 1129 aNew.SetWidth( nLeft ); 1130 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1131 1132 { 1133 const SfxPoolItem* pItem; 1134 if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetAttrSet() 1135 .GetItemState( RES_BOX, sal_False, &pItem )) 1136 { 1137 SvxBoxItem aBox( *(SvxBoxItem*)pItem ); 1138 aBox.SetLine( 0, BOX_LINE_RIGHT ); 1139 pBox->GetFrmFmt()->SetFmtAttr( aBox ); 1140 } 1141 } 1142 1143 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ]; 1144 aNew.SetWidth( nWidth ); 1145 pBox->ClaimFrmFmt(); 1146 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1147 1148 if( pUndo ) 1149 pUndo->AddNewBox( pBox->GetSttIdx() ); 1150 1151 // diese Box ist selektiert 1152 pLastBox = pBox; 1153 rBoxes.Insert( pBox ); 1154 aPosArr.Insert( 1155 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(), 1156 pBox, bVert ) ); 1157 1158 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos+1 ]; 1159 aNew.SetWidth( nRight ); 1160 pBox->ClaimFrmFmt(); 1161 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1162 1163 if( pUndo ) 1164 pUndo->AddNewBox( pBox->GetSttIdx() ); 1165 } 1166 // oder reicht die rechte Kante der Box in den 1167 // selektierten Bereich? 1168 else if( ( pCell->Frm().Right() - COLFUZZY ) < rUnion.Right() && 1169 ( pCell->Frm().Right() - COLFUZZY ) > rUnion.Left() && 1170 ( pCell->Frm().Left() + COLFUZZY ) < rUnion.Left() ) 1171 { 1172 // dann muss eine neue Box einfuegt und die 1173 // Breiten angepasst werden 1174 sal_uInt16 nInsPos = pBox->GetUpper()->GetTabBoxes(). 1175 C40_GETPOS( SwTableBox, pBox )+1; 1176 lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 1 ); 1177 1178 SwFmtFrmSize aNew(pBox->GetFrmFmt()->GetFrmSize() ); 1179 long nLeft = rUnion.Left() - pCell->Frm().Left(), 1180 nRight = pCell->Frm().Right() - rUnion.Left(); 1181 1182 nLeft = nLeft * aNew.GetWidth() / 1183 pCell->Frm().Width(); 1184 nRight = nRight * aNew.GetWidth() / 1185 pCell->Frm().Width(); 1186 1187 aNew.SetWidth( nLeft ); 1188 pBox->ClaimFrmFmt()->SetFmtAttr( aNew ); 1189 1190 // diese Box ist selektiert 1191 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ]; 1192 aNew.SetWidth( nRight ); 1193 pBox->ClaimFrmFmt(); 1194 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1195 1196 pLastBox = pBox; 1197 rBoxes.Insert( pBox ); 1198 aPosArr.Insert( _CmpLPt( Point( rUnion.Left(), 1199 pCell->Frm().Top()), pBox, bVert )); 1200 1201 if( pUndo ) 1202 pUndo->AddNewBox( pBox->GetSttIdx() ); 1203 } 1204 } 1205 if ( pCell->GetNext() ) 1206 { 1207 pCell = (const SwLayoutFrm*)pCell->GetNext(); 1208 // --> FME 2005-11-03 #125288# Check if table cell is not empty 1209 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) 1210 pCell = pCell->FirstCell(); 1211 } 1212 else 1213 pCell = ::lcl_FindNextCellFrm( pCell ); 1214 } 1215 } 1216 pRow = (const SwLayoutFrm*)pRow->GetNext(); 1217 } 1218 } 1219 1220 // keine SSelection / keine gefundenen Boxen 1221 if( 1 >= rBoxes.Count() ) 1222 return; 1223 1224 // dann suche mal alle Boxen, die nebeneinander liegen, und verbinde 1225 // deren Inhalte mit Blanks. Alle untereinander liegende werden als 1226 // Absaetze zusammengefasst 1227 1228 // 1. Loesung: gehe ueber das Array und 1229 // alle auf der gleichen Y-Ebene werden mit Blanks getrennt 1230 // alle anderen werden als Absaetze getrennt. 1231 sal_Bool bCalcWidth = sal_True; 1232 const SwTableBox* pFirstBox = aPosArr[ 0 ].pSelBox; 1233 1234 // JP 27.03.98: Optimierung - falls die Boxen einer Line leer sind, 1235 // dann werden jetzt dafuer keine Blanks und 1236 // kein Umbruch mehr eingefuegt. 1237 //Block damit SwPaM, SwPosition vom Stack geloescht werden 1238 { 1239 SwPaM aPam( pDoc->GetNodes() ); 1240 1241 #if defined( DEL_ONLY_EMPTY_LINES ) 1242 nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth(); 1243 sal_Bool bEmptyLine = sal_True; 1244 sal_uInt16 n, nSttPos = 0; 1245 1246 for( n = 0; n < aPosArr.Count(); ++n ) 1247 { 1248 const _CmpLPt& rPt = aPosArr[ n ]; 1249 if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // gleiche Ebene ? 1250 { 1251 if( bEmptyLine && !IsEmptyBox( *rPt.pSelBox, aPam )) 1252 bEmptyLine = sal_False; 1253 if( bCalcWidth ) 1254 nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth(); 1255 } 1256 else 1257 { 1258 if( bCalcWidth && n ) 1259 bCalcWidth = sal_False; // eine Zeile fertig 1260 1261 if( bEmptyLine && nSttPos < n ) 1262 { 1263 // dann ist die gesamte Line leer und braucht 1264 // nicht mit Blanks aufgefuellt und als Absatz 1265 // eingefuegt werden. 1266 if( pUndo ) 1267 for( sal_uInt16 i = nSttPos; i < n; ++i ) 1268 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1269 1270 aPosArr.Remove( nSttPos, n - nSttPos ); 1271 n = nSttPos; 1272 } 1273 else 1274 nSttPos = n; 1275 1276 bEmptyLine = IsEmptyBox( *aPosArr[n].pSelBox, aPam ); 1277 } 1278 } 1279 if( bEmptyLine && nSttPos < n ) 1280 { 1281 if( pUndo ) 1282 for( sal_uInt16 i = nSttPos; i < n; ++i ) 1283 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1284 aPosArr.Remove( nSttPos, n - nSttPos ); 1285 } 1286 #elsif defined( DEL_EMPTY_BOXES_AT_START_AND_END ) 1287 1288 nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth(); 1289 sal_uInt16 n, nSttPos = 0, nSEndPos = 0, nESttPos = 0; 1290 1291 for( n = 0; n < aPosArr.Count(); ++n ) 1292 { 1293 const _CmpLPt& rPt = aPosArr[ n ]; 1294 if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // gleiche Ebene ? 1295 { 1296 sal_Bool bEmptyBox = IsEmptyBox( *rPt.pSelBox, aPam ); 1297 if( bEmptyBox ) 1298 { 1299 if( nSEndPos == n ) // der Anfang ist leer 1300 nESttPos = ++nSEndPos; 1301 } 1302 else // das Ende kann leer sein 1303 nESttPos = n+1; 1304 1305 if( bCalcWidth ) 1306 nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth(); 1307 } 1308 else 1309 { 1310 if( bCalcWidth && n ) 1311 bCalcWidth = sal_False; // eine Zeile fertig 1312 1313 // zuerst die vom Anfang 1314 if( nSttPos < nSEndPos ) 1315 { 1316 // dann ist der vorder Teil der Line leer und braucht 1317 // nicht mit Blanks aufgefuellt werden. 1318 if( pUndo ) 1319 for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i ) 1320 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1321 1322 sal_uInt16 nCnt = nSEndPos - nSttPos; 1323 aPosArr.Remove( nSttPos, nCnt ); 1324 nESttPos -= nCnt; 1325 n -= nCnt; 1326 } 1327 1328 if( nESttPos < n ) 1329 { 1330 // dann ist der vorder Teil der Line leer und braucht 1331 // nicht mit Blanks aufgefuellt werden. 1332 if( pUndo ) 1333 for( sal_uInt16 i = nESttPos; i < n; ++i ) 1334 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1335 1336 sal_uInt16 nCnt = n - nESttPos; 1337 aPosArr.Remove( nESttPos, nCnt ); 1338 n -= nCnt; 1339 } 1340 1341 nSttPos = nSEndPos = nESttPos = n; 1342 if( IsEmptyBox( *aPosArr[n].pSelBox, aPam )) 1343 ++nSEndPos; 1344 else 1345 ++nESttPos; 1346 } 1347 } 1348 1349 // zuerst die vom Anfang 1350 if( nSttPos < nSEndPos ) 1351 { 1352 // dann ist der vorder Teil der Line leer und braucht 1353 // nicht mit Blanks aufgefuellt werden. 1354 if( pUndo ) 1355 for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i ) 1356 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1357 1358 sal_uInt16 nCnt = nSEndPos - nSttPos; 1359 aPosArr.Remove( nSttPos, nCnt ); 1360 nESttPos -= nCnt; 1361 n -= nCnt; 1362 } 1363 if( nESttPos < n ) 1364 { 1365 // dann ist der vorder Teil der Line leer und braucht 1366 // nicht mit Blanks aufgefuellt werden. 1367 if( pUndo ) 1368 for( sal_uInt16 i = nESttPos; i < n; ++i ) 1369 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1370 1371 sal_uInt16 nCnt = n - nESttPos; 1372 aPosArr.Remove( nESttPos, nCnt ); 1373 } 1374 #else 1375 // DEL_ALL_EMPTY_BOXES 1376 1377 nWidth = 0; 1378 long nY = aPosArr.Count() ? 1379 ( bVert ? 1380 aPosArr[ 0 ].X() : 1381 aPosArr[ 0 ].Y() ) : 1382 0; 1383 1384 for( sal_uInt16 n = 0; n < aPosArr.Count(); ++n ) 1385 { 1386 const _CmpLPt& rPt = aPosArr[ n ]; 1387 if( bCalcWidth ) 1388 { 1389 if( nY == ( bVert ? rPt.X() : rPt.Y() ) ) // gleiche Ebene ? 1390 nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth(); 1391 else 1392 bCalcWidth = sal_False; // eine Zeile fertig 1393 } 1394 1395 if( IsEmptyBox( *rPt.pSelBox, aPam ) ) 1396 { 1397 if( pUndo ) 1398 pUndo->SaveCollection( *rPt.pSelBox ); 1399 1400 aPosArr.Remove( n, 1 ); 1401 --n; 1402 } 1403 } 1404 #endif 1405 } 1406 1407 // lege schon mal die neue Box an 1408 { 1409 SwTableBox* pTmpBox = rBoxes[0]; 1410 SwTableLine* pInsLine = pTmpBox->GetUpper(); 1411 sal_uInt16 nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pTmpBox ); 1412 1413 lcl_InsTblBox( pTblNd, pDoc, pTmpBox, nInsPos ); 1414 (*ppMergeBox) = pInsLine->GetTabBoxes()[ nInsPos ]; 1415 pInsLine->GetTabBoxes().Remove( nInsPos ); // wieder austragen 1416 (*ppMergeBox)->SetUpper( 0 ); 1417 (*ppMergeBox)->ClaimFrmFmt(); 1418 1419 // setze die Umrandung: von der 1. Box die linke/obere von der 1420 // letzten Box die rechte/untere Kante: 1421 if( pLastBox && pFirstBox ) 1422 { 1423 SvxBoxItem aBox( pFirstBox->GetFrmFmt()->GetBox() ); 1424 const SvxBoxItem& rBox = pLastBox->GetFrmFmt()->GetBox(); 1425 aBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT ); 1426 aBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM ); 1427 if( aBox.GetLeft() || aBox.GetTop() || 1428 aBox.GetRight() || aBox.GetBottom() ) 1429 (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( aBox ); 1430 } 1431 } 1432 1433 //Block damit SwPaM, SwPosition vom Stack geloescht werden 1434 if( aPosArr.Count() ) 1435 { 1436 SwTxtNode* pTxtNd = 0; 1437 SwPosition aInsPos( *(*ppMergeBox)->GetSttNd() ); 1438 SwNodeIndex& rInsPosNd = aInsPos.nNode; 1439 1440 SwPaM aPam( aInsPos ); 1441 1442 for( sal_uInt16 n = 0; n < aPosArr.Count(); ++n ) 1443 { 1444 const _CmpLPt& rPt = aPosArr[ n ]; 1445 aPam.GetPoint()->nNode.Assign( *rPt.pSelBox->GetSttNd()-> 1446 EndOfSectionNode(), -1 ); 1447 SwCntntNode* pCNd = aPam.GetCntntNode(); 1448 sal_uInt16 nL = pCNd ? pCNd->Len() : 0; 1449 aPam.GetPoint()->nContent.Assign( pCNd, nL ); 1450 1451 SwNodeIndex aSttNdIdx( *rPt.pSelBox->GetSttNd(), 1 ); 1452 // ein Node muss in der Box erhalten bleiben (sonst wird beim 1453 // Move die gesamte Section geloescht) 1454 bool const bUndo(pDoc->GetIDocumentUndoRedo().DoesUndo()); 1455 if( pUndo ) 1456 { 1457 pDoc->GetIDocumentUndoRedo().DoUndo(false); 1458 } 1459 pDoc->AppendTxtNode( *aPam.GetPoint() ); 1460 if( pUndo ) 1461 { 1462 pDoc->GetIDocumentUndoRedo().DoUndo(bUndo); 1463 } 1464 SwNodeRange aRg( aSttNdIdx, aPam.GetPoint()->nNode ); 1465 rInsPosNd++; 1466 if( pUndo ) 1467 pUndo->MoveBoxCntnt( pDoc, aRg, rInsPosNd ); 1468 else 1469 { 1470 pDoc->MoveNodeRange( aRg, rInsPosNd, 1471 IDocumentContentOperations::DOC_MOVEDEFAULT ); 1472 } 1473 // wo steht jetzt aInsPos ?? 1474 1475 if( bCalcWidth ) 1476 bCalcWidth = sal_False; // eine Zeile fertig 1477 1478 // den initialen TextNode ueberspringen 1479 rInsPosNd.Assign( pDoc->GetNodes(), 1480 rInsPosNd.GetNode().EndOfSectionIndex() - 2 ); 1481 pTxtNd = rInsPosNd.GetNode().GetTxtNode(); 1482 if( pTxtNd ) 1483 aInsPos.nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() ); 1484 } 1485 1486 // in der MergeBox sollte jetzt der gesamte Text stehen 1487 // loesche jetzt noch den initialen TextNode 1488 ASSERT( (*ppMergeBox)->GetSttIdx()+2 < 1489 (*ppMergeBox)->GetSttNd()->EndOfSectionIndex(), 1490 "leere Box" ); 1491 SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 ); 1492 pDoc->GetNodes().Delete( aIdx, 1 ); 1493 } 1494 1495 // setze die Breite der Box 1496 (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 )); 1497 if( pUndo ) 1498 pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() ); 1499 } 1500 1501 1502 static sal_Bool lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara ); 1503 1504 static sal_Bool lcl_CheckRow( const _FndLine*& rpFndLine, void* pPara ) 1505 { 1506 ((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CheckCol, pPara ); 1507 return *(sal_Bool*)pPara; 1508 } 1509 1510 static sal_Bool lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara ) 1511 { 1512 if( !rpFndBox->GetBox()->GetSttNd() ) 1513 { 1514 if( rpFndBox->GetLines().Count() != 1515 rpFndBox->GetBox()->GetTabLines().Count() ) 1516 *((sal_Bool*)pPara) = sal_False; 1517 else 1518 ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CheckRow, pPara ); 1519 } 1520 // Box geschuetzt ?? 1521 else if( rpFndBox->GetBox()->GetFrmFmt()->GetProtect().IsCntntProtected() ) 1522 *((sal_Bool*)pPara) = sal_False; 1523 return *(sal_Bool*)pPara; 1524 } 1525 1526 1527 sal_uInt16 CheckMergeSel( const SwPaM& rPam ) 1528 { 1529 SwSelBoxes aBoxes; 1530 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht 1531 // richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert, 1532 // das die 1. Headline mit drin ist. 1533 Point aPt; 1534 const SwCntntNode* pCntNd = rPam.GetCntntNode(); 1535 const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 1536 &aPt )->GetUpper(); 1537 pCntNd = rPam.GetCntntNode(sal_False); 1538 const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 1539 &aPt )->GetUpper(); 1540 GetTblSel( pStart, pEnd, aBoxes, 0 ); 1541 return CheckMergeSel( aBoxes ); 1542 } 1543 1544 sal_uInt16 CheckMergeSel( const SwSelBoxes& rBoxes ) 1545 { 1546 sal_uInt16 eRet = TBLMERGE_NOSELECTION; 1547 if( rBoxes.Count() ) 1548 { 1549 eRet = TBLMERGE_OK; 1550 1551 _FndBox aFndBox( 0, 0 ); 1552 _FndPara aPara( rBoxes, &aFndBox ); 1553 const SwTableNode* pTblNd = aPara.rBoxes[0]->GetSttNd()->FindTableNode(); 1554 ((SwTable&)pTblNd->GetTable()).GetTabLines().ForEach( 1555 &_FndLineCopyCol, &aPara ); 1556 if( aFndBox.GetLines().Count() ) 1557 { 1558 sal_Bool bMergeSelOk = sal_True; 1559 _FndBox* pFndBox = &aFndBox; 1560 _FndLine* pFndLine = 0; 1561 while( pFndBox && 1 == pFndBox->GetLines().Count() ) 1562 { 1563 pFndLine = pFndBox->GetLines()[0]; 1564 if( 1 == pFndLine->GetBoxes().Count() ) 1565 pFndBox = pFndLine->GetBoxes()[0]; 1566 else 1567 pFndBox = 0; 1568 } 1569 if( pFndBox ) 1570 pFndBox->GetLines().ForEach( &lcl_CheckRow, &bMergeSelOk ); 1571 else if( pFndLine ) 1572 pFndLine->GetBoxes().ForEach( &lcl_CheckCol, &bMergeSelOk ); 1573 if( !bMergeSelOk ) 1574 eRet = TBLMERGE_TOOCOMPLEX; 1575 } 1576 else 1577 eRet = TBLMERGE_NOSELECTION; 1578 } 1579 return eRet; 1580 } 1581 1582 //Ermittelt die von einer Tabellenselektion betroffenen Tabellen und die 1583 //Union-Rechteckte der Selektionen - auch fuer aufgespaltene Tabellen. 1584 SV_IMPL_PTRARR( SwSelUnions, SwSelUnion* ); 1585 1586 SwTwips lcl_CalcWish( const SwLayoutFrm *pCell, long nWish, 1587 const long nAct ) 1588 { 1589 const SwLayoutFrm *pTmp = pCell; 1590 if ( !nWish ) 1591 nWish = 1; 1592 1593 const sal_Bool bRTL = pCell->IsRightToLeft(); 1594 SwTwips nRet = bRTL ? 1595 nAct - pCell->Frm().Width() : 1596 0; 1597 1598 while ( pTmp ) 1599 { 1600 while ( pTmp->GetPrev() ) 1601 { 1602 pTmp = (SwLayoutFrm*)pTmp->GetPrev(); 1603 long nTmp = pTmp->GetFmt()->GetFrmSize().GetWidth(); 1604 nRet += ( bRTL ? ( -1 ) : 1 ) * nTmp * nAct / nWish; 1605 } 1606 pTmp = pTmp->GetUpper()->GetUpper(); 1607 if ( pTmp && !pTmp->IsCellFrm() ) 1608 pTmp = 0; 1609 } 1610 return nRet; 1611 } 1612 1613 void lcl_FindStartEndRow( const SwLayoutFrm *&rpStart, 1614 const SwLayoutFrm *&rpEnd, 1615 const int bChkProtected ) 1616 { 1617 //Start an den Anfang seiner Zeile setzen. 1618 //End an das Ende seiner Zeile setzen. 1619 rpStart = (SwLayoutFrm*)rpStart->GetUpper()->Lower(); 1620 while ( rpEnd->GetNext() ) 1621 rpEnd = (SwLayoutFrm*)rpEnd->GetNext(); 1622 1623 SvPtrarr aSttArr( 8, 8 ), aEndArr( 8, 8 ); 1624 const SwLayoutFrm *pTmp; 1625 for( pTmp = rpStart; (FRM_CELL|FRM_ROW) & pTmp->GetType(); 1626 pTmp = pTmp->GetUpper() ) 1627 { 1628 void* p = (void*)pTmp; 1629 aSttArr.Insert( p, 0 ); 1630 } 1631 for( pTmp = rpEnd; (FRM_CELL|FRM_ROW) & pTmp->GetType(); 1632 pTmp = pTmp->GetUpper() ) 1633 { 1634 void* p = (void*)pTmp; 1635 aEndArr.Insert( p, 0 ); 1636 } 1637 1638 for( sal_uInt16 n = 0; n < aEndArr.Count() && n < aSttArr.Count(); ++n ) 1639 if( aSttArr[ n ] != aEndArr[ n ] ) 1640 { 1641 // first unequal line or box - all odds are 1642 if( n & 1 ) // 1, 3, 5, ... are boxes 1643 { 1644 rpStart = (SwLayoutFrm*)aSttArr[ n ]; 1645 rpEnd = (SwLayoutFrm*)aEndArr[ n ]; 1646 } 1647 else // 0, 2, 4, ... are lines 1648 { 1649 // check if start & end line are the first & last Line of the 1650 // box. If not return these cells. 1651 // Else the hole line with all Boxes has to be deleted. 1652 rpStart = (SwLayoutFrm*)aSttArr[ n+1 ]; 1653 rpEnd = (SwLayoutFrm*)aEndArr[ n+1 ]; 1654 if( n ) 1655 { 1656 const SwCellFrm* pCellFrm = (SwCellFrm*)aSttArr[ n-1 ]; 1657 const SwTableLines& rLns = pCellFrm-> 1658 GetTabBox()->GetTabLines(); 1659 if( rLns[ 0 ] == ((SwRowFrm*)aSttArr[ n ])->GetTabLine() && 1660 rLns[ rLns.Count() - 1 ] == 1661 ((SwRowFrm*)aEndArr[ n ])->GetTabLine() ) 1662 { 1663 rpStart = rpEnd = pCellFrm; 1664 while ( rpStart->GetPrev() ) 1665 rpStart = (SwLayoutFrm*)rpStart->GetPrev(); 1666 while ( rpEnd->GetNext() ) 1667 rpEnd = (SwLayoutFrm*)rpEnd->GetNext(); 1668 } 1669 } 1670 } 1671 break; 1672 } 1673 1674 if( !bChkProtected ) // geschuetzte Zellen beachten ? 1675 return; 1676 1677 1678 //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen. 1679 while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() ) 1680 rpStart = (SwLayoutFrm*)rpStart->GetNext(); 1681 while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() ) 1682 rpEnd = (SwLayoutFrm*)rpEnd->GetPrev(); 1683 } 1684 1685 1686 void lcl_FindStartEndCol( const SwLayoutFrm *&rpStart, 1687 const SwLayoutFrm *&rpEnd, 1688 const int bChkProtected ) 1689 { 1690 //Start und End senkrecht bis an den Rand der Tabelle denken; es muss 1691 //die Gesamttabelle betrachtet werden, also inklusive Masters und 1692 //Follows. 1693 //Fuer den Start brauchen wir den Mutter-TabellenFrm. 1694 if( !rpStart ) 1695 return; 1696 const SwTabFrm *pOrg = rpStart->FindTabFrm(); 1697 const SwTabFrm *pTab = pOrg; 1698 1699 SWRECTFN( pTab ) 1700 1701 sal_Bool bRTL = pTab->IsRightToLeft(); 1702 const long nTmpWish = pOrg->GetFmt()->GetFrmSize().GetWidth(); 1703 const long nWish = ( nTmpWish > 0 ) ? nTmpWish : 1; 1704 1705 while ( pTab->IsFollow() ) 1706 { 1707 const SwFrm *pTmp = pTab->FindPrev(); 1708 ASSERT( pTmp->IsTabFrm(), "Vorgaenger vom Follow nicht der Master." ); 1709 pTab = (const SwTabFrm*)pTmp; 1710 } 1711 1712 SwTwips nSX = 0; 1713 SwTwips nSX2 = 0; 1714 1715 if ( pTab->GetTable()->IsNewModel() ) 1716 { 1717 nSX = (rpStart->Frm().*fnRect->fnGetLeft )(); 1718 nSX2 = (rpStart->Frm().*fnRect->fnGetRight)(); 1719 } 1720 else 1721 { 1722 const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)(); 1723 nSX = ::lcl_CalcWish( rpStart, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)(); 1724 nSX2 = nSX + (rpStart->GetFmt()->GetFrmSize().GetWidth() * nPrtWidth / nWish); 1725 } 1726 1727 const SwLayoutFrm *pTmp = pTab->FirstCell(); 1728 1729 while ( pTmp && 1730 (!pTmp->IsCellFrm() || 1731 ( ( ! bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() < nSX && 1732 (pTmp->Frm().*fnRect->fnGetRight)()< nSX2 ) || 1733 ( bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() > nSX && 1734 (pTmp->Frm().*fnRect->fnGetRight)()> nSX2 ) ) ) ) 1735 pTmp = pTmp->GetNextLayoutLeaf(); 1736 1737 if ( pTmp ) 1738 rpStart = pTmp; 1739 1740 pTab = pOrg; 1741 1742 const SwTabFrm* pLastValidTab = pTab; 1743 while ( pTab->GetFollow() ) 1744 { 1745 // 1746 // Check if pTab->GetFollow() is a valid follow table: 1747 // Only follow tables with at least on non-FollowFlowLine 1748 // should be considered. 1749 // 1750 if ( pTab->HasFollowFlowLine() ) 1751 { 1752 pTab = pTab->GetFollow(); 1753 const SwFrm* pTmpRow = pTab->GetFirstNonHeadlineRow(); 1754 if ( pTmpRow && pTmpRow->GetNext() ) 1755 pLastValidTab = pTab; 1756 } 1757 else 1758 pLastValidTab = pTab = pTab->GetFollow(); 1759 } 1760 pTab = pLastValidTab; 1761 1762 SwTwips nEX = 0; 1763 1764 if ( pTab->GetTable()->IsNewModel() ) 1765 { 1766 nEX = (rpEnd->Frm().*fnRect->fnGetLeft )(); 1767 } 1768 else 1769 { 1770 const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)(); 1771 nEX = ::lcl_CalcWish( rpEnd, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)(); 1772 } 1773 1774 const SwCntntFrm* pLastCntnt = pTab->FindLastCntnt(); 1775 rpEnd = pLastCntnt ? pLastCntnt->GetUpper() : 0; 1776 // --> FME 2006-07-17 #134385# Made code robust. If pTab does not have a lower, 1777 // we would crash here. 1778 if ( !pLastCntnt ) return; 1779 // <-- 1780 1781 while( !rpEnd->IsCellFrm() ) 1782 rpEnd = rpEnd->GetUpper(); 1783 1784 while ( ( bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() < nEX ) || 1785 ( ! bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) ) 1786 { 1787 const SwLayoutFrm* pTmpLeaf = rpEnd->GetPrevLayoutLeaf(); 1788 if( !pTmpLeaf || !pTab->IsAnLower( pTmpLeaf ) ) 1789 break; 1790 rpEnd = pTmpLeaf; 1791 } 1792 1793 if( !bChkProtected ) // geschuetzte Zellen beachten ? 1794 return; 1795 1796 //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen. 1797 //Also muss ggf. nocheinmal rueckwaerts gesucht werden. 1798 while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() ) 1799 { 1800 const SwLayoutFrm *pTmpLeaf = rpStart; 1801 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf(); 1802 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )//erstmal die Zeile ueberspr. 1803 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf(); 1804 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nSX && 1805 (pTmpLeaf->Frm().*fnRect->fnGetRight)()< nSX2 ) 1806 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf(); 1807 const SwTabFrm *pTmpTab = rpStart->FindTabFrm(); 1808 if ( !pTmpTab->IsAnLower( pTmpLeaf ) ) 1809 { 1810 pTmpTab = pTmpTab->GetFollow(); 1811 rpStart = pTmpTab->FirstCell(); 1812 while ( (rpStart->Frm().*fnRect->fnGetLeft)() < nSX && 1813 (rpStart->Frm().*fnRect->fnGetRight)()< nSX2 ) 1814 rpStart = rpStart->GetNextLayoutLeaf(); 1815 } 1816 else 1817 rpStart = pTmpLeaf; 1818 } 1819 while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() ) 1820 { 1821 const SwLayoutFrm *pTmpLeaf = rpEnd; 1822 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf(); 1823 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nEX )//erstmal die Zeile ueberspr. 1824 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf(); 1825 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX ) 1826 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf(); 1827 const SwTabFrm *pTmpTab = rpEnd->FindTabFrm(); 1828 if ( !pTmpLeaf || !pTmpTab->IsAnLower( pTmpLeaf ) ) 1829 { 1830 pTmpTab = (const SwTabFrm*)pTmpTab->FindPrev(); 1831 ASSERT( pTmpTab->IsTabFrm(), "Vorgaenger vom Follow nicht der Master."); 1832 rpEnd = pTmpTab->FindLastCntnt()->GetUpper(); 1833 while( !rpEnd->IsCellFrm() ) 1834 rpEnd = rpEnd->GetUpper(); 1835 while ( (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) 1836 rpEnd = rpEnd->GetPrevLayoutLeaf(); 1837 } 1838 else 1839 rpEnd = pTmpLeaf; 1840 } 1841 } 1842 1843 1844 void MakeSelUnions( SwSelUnions& rUnions, const SwLayoutFrm *pStart, 1845 const SwLayoutFrm *pEnd, const SwTblSearchType eSearchType ) 1846 { 1847 while ( pStart && !pStart->IsCellFrm() ) 1848 pStart = pStart->GetUpper(); 1849 while ( pEnd && !pEnd->IsCellFrm() ) 1850 pEnd = pEnd->GetUpper(); 1851 1852 // #112697# Robust: 1853 if ( !pStart || !pEnd ) 1854 { 1855 ASSERT( false, "MakeSelUnions with pStart or pEnd not in CellFrm" ) 1856 return; 1857 } 1858 1859 const SwTabFrm *pTable = pStart->FindTabFrm(); 1860 const SwTabFrm *pEndTable = pEnd->FindTabFrm(); 1861 if( !pTable || !pEndTable ) 1862 return; 1863 sal_Bool bExchange = sal_False; 1864 1865 if ( pTable != pEndTable ) 1866 { 1867 if ( !pTable->IsAnFollow( pEndTable ) ) 1868 { 1869 ASSERT( pEndTable->IsAnFollow( pTable ), "Tabkette verknotet." ); 1870 bExchange = sal_True; 1871 } 1872 } 1873 else 1874 { 1875 SWRECTFN( pTable ) 1876 long nSttTop = (pStart->Frm().*fnRect->fnGetTop)(); 1877 long nEndTop = (pEnd->Frm().*fnRect->fnGetTop)(); 1878 if( nSttTop == nEndTop ) 1879 { 1880 if( (pStart->Frm().*fnRect->fnGetLeft)() > 1881 (pEnd->Frm().*fnRect->fnGetLeft)() ) 1882 bExchange = sal_True; 1883 } 1884 else if( bVert == ( nSttTop < nEndTop ) ) 1885 bExchange = sal_True; 1886 } 1887 if ( bExchange ) 1888 { 1889 const SwLayoutFrm *pTmp = pStart; 1890 pStart = pEnd; 1891 pEnd = pTmp; 1892 //pTable und pEndTable nicht umsortieren, werden unten neu gesetzt. 1893 //MA: 28. Dec. 93 Bug: 5190 1894 } 1895 1896 //Start und End sind jetzt huebsch sortiert, jetzt muessen sie falls 1897 //erwuenscht noch versetzt werden. 1898 if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) ) 1899 ::lcl_FindStartEndRow( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType ); 1900 else if( nsSwTblSearchType::TBLSEARCH_COL == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) ) 1901 ::lcl_FindStartEndCol( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType ); 1902 1903 // --> FME 2006-07-17 #134385# Made code robust. 1904 if ( !pEnd ) return; 1905 // <-- 1906 1907 //neu besorgen, da sie jetzt verschoben sind. MA: 28. Dec. 93 Bug 5190 1908 pTable = pStart->FindTabFrm(); 1909 pEndTable = pEnd->FindTabFrm(); 1910 1911 const long nStSz = pStart->GetFmt()->GetFrmSize().GetWidth(); 1912 const long nEdSz = pEnd->GetFmt()->GetFrmSize().GetWidth(); 1913 const long nWish = Max( 1L, pTable->GetFmt()->GetFrmSize().GetWidth() ); 1914 while ( pTable ) 1915 { 1916 SWRECTFN( pTable ) 1917 const long nOfst = (pTable->*fnRect->fnGetPrtLeft)(); 1918 const long nPrtWidth = (pTable->Prt().*fnRect->fnGetWidth)(); 1919 long nSt1 = ::lcl_CalcWish( pStart, nWish, nPrtWidth ) + nOfst; 1920 long nEd1 = ::lcl_CalcWish( pEnd, nWish, nPrtWidth ) + nOfst; 1921 1922 if ( nSt1 <= nEd1 ) 1923 nEd1 += (long)((nEdSz * nPrtWidth) / nWish) - 1; 1924 else 1925 nSt1 += (long)((nStSz * nPrtWidth) / nWish) - 1; 1926 1927 long nSt2; 1928 long nEd2; 1929 if( pTable->IsAnLower( pStart ) ) 1930 nSt2 = (pStart->Frm().*fnRect->fnGetTop)(); 1931 else 1932 nSt2 = (pTable->Frm().*fnRect->fnGetTop)(); 1933 if( pTable->IsAnLower( pEnd ) ) 1934 nEd2 = (pEnd->Frm().*fnRect->fnGetBottom)(); 1935 else 1936 nEd2 = (pTable->Frm().*fnRect->fnGetBottom)(); 1937 Point aSt, aEd; 1938 if( nSt1 > nEd1 ) 1939 { 1940 long nTmp = nSt1; 1941 nSt1 = nEd1; 1942 nEd1 = nTmp; 1943 } 1944 if( nSt2 > nEd2 ) 1945 { 1946 long nTmp = nSt2; 1947 nSt2 = nEd2; 1948 nEd2 = nTmp; 1949 } 1950 if( bVert ) 1951 { 1952 aSt = Point( nSt2, nSt1 ); 1953 aEd = Point( nEd2, nEd1 ); 1954 } 1955 else 1956 { 1957 aSt = Point( nSt1, nSt2 ); 1958 aEd = Point( nEd1, nEd2 ); 1959 } 1960 1961 const Point aDiff( aEd - aSt ); 1962 SwRect aUnion( aSt, Size( aDiff.X(), aDiff.Y() ) ); 1963 aUnion.Justify(); 1964 1965 // fuers 1966 if( !(nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT & eSearchType )) 1967 { 1968 //Leider ist die Union jetzt mit Rundungsfehlern behaftet und dadurch 1969 //wuerden beim Split/Merge fehlertraechtige Umstaende entstehen. 1970 //Um dies zu vermeiden werden jetzt fuer die Table die erste und 1971 //letzte Zelle innerhalb der Union ermittelt und aus genau deren 1972 //Werten wird die Union neu gebildet. 1973 const SwLayoutFrm* pRow = pTable->IsFollow() ? 1974 pTable->GetFirstNonHeadlineRow() : 1975 (const SwLayoutFrm*)pTable->Lower(); 1976 1977 while ( pRow && !pRow->Frm().IsOver( aUnion ) ) 1978 pRow = (SwLayoutFrm*)pRow->GetNext(); 1979 1980 // --> FME 2004-07-26 #i31976# 1981 // A follow flow row may contain emtpy cells. These are not 1982 // considered by FirstCell(). Therefore we have to find 1983 // the first cell manually: 1984 const SwFrm* pTmpCell = 0; 1985 if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() ) 1986 { 1987 const SwFrm* pTmpRow = pRow; 1988 while ( pTmpRow && pTmpRow->IsRowFrm() ) 1989 { 1990 pTmpCell = static_cast<const SwRowFrm*>(pTmpRow)->Lower(); 1991 pTmpRow = static_cast<const SwCellFrm*>(pTmpCell)->Lower(); 1992 } 1993 ASSERT( !pTmpCell || pTmpCell->IsCellFrm(), "Lower of rowframe != cellframe?!" ) 1994 } 1995 // <-- 1996 1997 const SwLayoutFrm* pFirst = pTmpCell ? 1998 static_cast<const SwLayoutFrm*>(pTmpCell) : 1999 pRow ? 2000 pRow->FirstCell() : 2001 0; 2002 2003 while ( pFirst && !::IsFrmInTblSel( aUnion, pFirst ) ) 2004 { 2005 if ( pFirst->GetNext() ) 2006 { 2007 pFirst = (const SwLayoutFrm*)pFirst->GetNext(); 2008 if ( pFirst->Lower() && pFirst->Lower()->IsRowFrm() ) 2009 pFirst = pFirst->FirstCell(); 2010 } 2011 else 2012 pFirst = ::lcl_FindNextCellFrm( pFirst ); 2013 } 2014 const SwLayoutFrm* pLast = 0; 2015 const SwFrm* pLastCntnt = pTable->FindLastCntnt(); 2016 if ( pLastCntnt ) 2017 pLast = ::lcl_FindCellFrm( pLastCntnt->GetUpper() ); 2018 2019 while ( pLast && !::IsFrmInTblSel( aUnion, pLast ) ) 2020 pLast = ::lcl_FindCellFrm( pLast->GetPrevLayoutLeaf() ); 2021 2022 if ( pFirst && pLast ) //Robust 2023 { 2024 aUnion = pFirst->Frm(); 2025 aUnion.Union( pLast->Frm() ); 2026 } 2027 else 2028 aUnion.Width( 0 ); 2029 } 2030 2031 if( (aUnion.*fnRect->fnGetWidth)() ) 2032 { 2033 SwSelUnion *pTmp = new SwSelUnion( aUnion, (SwTabFrm*)pTable ); 2034 rUnions.C40_INSERT( SwSelUnion, pTmp, rUnions.Count() ); 2035 } 2036 2037 pTable = pTable->GetFollow(); 2038 if ( pTable != pEndTable && pEndTable->IsAnFollow( pTable ) ) 2039 pTable = 0; 2040 } 2041 } 2042 2043 sal_Bool CheckSplitCells( const SwCrsrShell& rShell, sal_uInt16 nDiv, 2044 const SwTblSearchType eSearchType ) 2045 { 2046 if( !rShell.IsTableMode() ) 2047 rShell.GetCrsr(); 2048 2049 return CheckSplitCells( *rShell.getShellCrsr(false), nDiv, eSearchType ); 2050 } 2051 2052 sal_Bool CheckSplitCells( const SwCursor& rCrsr, sal_uInt16 nDiv, 2053 const SwTblSearchType eSearchType ) 2054 { 2055 if( 1 >= nDiv ) 2056 return sal_False; 2057 2058 sal_uInt16 nMinValue = nDiv * MINLAY; 2059 2060 //Start- und Endzelle besorgen und den naechsten fragen. 2061 Point aPtPos, aMkPos; 2062 const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr); 2063 if( pShCrsr ) 2064 { 2065 aPtPos = pShCrsr->GetPtPos(); 2066 aMkPos = pShCrsr->GetMkPos(); 2067 } 2068 2069 const SwCntntNode* pCntNd = rCrsr.GetCntntNode(); 2070 const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 2071 &aPtPos )->GetUpper(); 2072 pCntNd = rCrsr.GetCntntNode(sal_False); 2073 const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 2074 &aMkPos )->GetUpper(); 2075 2076 SWRECTFN( pStart->GetUpper() ) 2077 2078 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. 2079 SwSelUnions aUnions; 2080 2081 ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType ); 2082 2083 //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen. 2084 for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) 2085 { 2086 SwSelUnion *pUnion = aUnions[i]; 2087 const SwTabFrm *pTable = pUnion->GetTable(); 2088 2089 // Skip any repeated headlines in the follow: 2090 const SwLayoutFrm* pRow = pTable->IsFollow() ? 2091 pTable->GetFirstNonHeadlineRow() : 2092 (const SwLayoutFrm*)pTable->Lower(); 2093 2094 while ( pRow ) 2095 { 2096 if ( pRow->Frm().IsOver( pUnion->GetUnion() ) ) 2097 { 2098 const SwLayoutFrm *pCell = pRow->FirstCell(); 2099 2100 while ( pCell && pRow->IsAnLower( pCell ) ) 2101 { 2102 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); 2103 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) 2104 { 2105 if( (pCell->Frm().*fnRect->fnGetWidth)() < nMinValue ) 2106 return sal_False; 2107 } 2108 2109 if ( pCell->GetNext() ) 2110 { 2111 pCell = (const SwLayoutFrm*)pCell->GetNext(); 2112 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) 2113 pCell = pCell->FirstCell(); 2114 } 2115 else 2116 pCell = ::lcl_FindNextCellFrm( pCell ); 2117 } 2118 } 2119 pRow = (const SwLayoutFrm*)pRow->GetNext(); 2120 } 2121 } 2122 return sal_True; 2123 } 2124 2125 // ------------------------------------------------------------------- 2126 // Diese Klassen kopieren die aktuelle Tabellen-Selektion (rBoxes) 2127 // unter Beibehaltung der Tabellen-Struktur in eine eigene Struktur 2128 // neu: SS zum gezielten Loeschen/Retaurieren des Layouts. 2129 2130 void lcl_InsertRow( SwTableLine &rLine, SwLayoutFrm *pUpper, SwFrm *pSibling ) 2131 { 2132 SwRowFrm *pRow = new SwRowFrm( rLine, pUpper ); 2133 if ( pUpper->IsTabFrm() && ((SwTabFrm*)pUpper)->IsFollow() ) 2134 { 2135 SwTabFrm* pTabFrm = (SwTabFrm*)pUpper; 2136 pTabFrm->FindMaster()->InvalidatePos(); //kann die Zeile vielleicht aufnehmen 2137 2138 if ( pSibling && pTabFrm->IsInHeadline( *pSibling ) ) 2139 { 2140 // Skip any repeated headlines in the follow: 2141 pSibling = pTabFrm->GetFirstNonHeadlineRow(); 2142 } 2143 } 2144 pRow->Paste( pUpper, pSibling ); 2145 pRow->RegistFlys(); 2146 } 2147 2148 2149 sal_Bool _FndBoxCopyCol( const SwTableBox*& rpBox, void* pPara ) 2150 { 2151 _FndPara* pFndPara = (_FndPara*)pPara; 2152 _FndBox* pFndBox = new _FndBox( (SwTableBox*)rpBox, pFndPara->pFndLine ); 2153 if( rpBox->GetTabLines().Count() ) 2154 { 2155 _FndPara aPara( *pFndPara, pFndBox ); 2156 pFndBox->GetBox()->GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); 2157 if( !pFndBox->GetLines().Count() ) 2158 { 2159 delete pFndBox; 2160 return sal_True; 2161 } 2162 } 2163 else 2164 { 2165 SwTableBoxPtr pSrch = (SwTableBoxPtr)rpBox; 2166 sal_uInt16 nFndPos; 2167 if( !pFndPara->rBoxes.Seek_Entry( pSrch, &nFndPos )) 2168 { 2169 delete pFndBox; 2170 return sal_True; 2171 } 2172 } 2173 pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, 2174 pFndPara->pFndLine->GetBoxes().Count() ); 2175 return sal_True; 2176 } 2177 2178 sal_Bool _FndLineCopyCol( const SwTableLine*& rpLine, void* pPara ) 2179 { 2180 _FndPara* pFndPara = (_FndPara*)pPara; 2181 _FndLine* pFndLine = new _FndLine( (SwTableLine*)rpLine, pFndPara->pFndBox ); 2182 _FndPara aPara( *pFndPara, pFndLine ); 2183 pFndLine->GetLine()->GetTabBoxes().ForEach( &_FndBoxCopyCol, &aPara ); 2184 if( pFndLine->GetBoxes().Count() ) 2185 { 2186 pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine, 2187 pFndPara->pFndBox->GetLines().Count() ); 2188 } 2189 else 2190 delete pFndLine; 2191 return sal_True; 2192 } 2193 2194 void _FndBox::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable ) 2195 { 2196 //Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich 2197 //setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen 2198 //sind, so bleiben die Pointer eben einfach 0. 2199 //Gesucht werden zunachst die Positionen der ersten/letzten betroffenen 2200 //Line im Array der SwTable. Damit die 0 fuer 'keine Line' verwand werden 2201 //kann werden die Positionen um 1 nach oben versetzt! 2202 2203 sal_uInt16 nStPos = USHRT_MAX; 2204 sal_uInt16 nEndPos= 0; 2205 2206 for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) 2207 { 2208 SwTableLine *pLine = rBoxes[i]->GetUpper(); 2209 while ( pLine->GetUpper() ) 2210 pLine = pLine->GetUpper()->GetUpper(); 2211 const sal_uInt16 nPos = rTable.GetTabLines().GetPos( 2212 (const SwTableLine*&)pLine ) + 1; 2213 2214 ASSERT( nPos != USHRT_MAX, "TableLine not found." ); 2215 2216 if( nStPos > nPos ) 2217 nStPos = nPos; 2218 2219 if( nEndPos < nPos ) 2220 nEndPos = nPos; 2221 } 2222 if ( nStPos > 1 ) 2223 pLineBefore = rTable.GetTabLines()[nStPos - 2]; 2224 if ( nEndPos < rTable.GetTabLines().Count() ) 2225 pLineBehind = rTable.GetTabLines()[nEndPos]; 2226 } 2227 2228 void _FndBox::SetTableLines( const SwTable &rTable ) 2229 { 2230 // Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich 2231 // setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen 2232 // sind, so bleiben die Pointer eben einfach 0. 2233 // Die Positionen der ersten/letzten betroffenen Line im Array der 2234 // SwTable steht in der FndBox. Damit die 0 fuer 'keine Line' verwand 2235 // werdenkann werden die Positionen um 1 nach oben versetzt! 2236 2237 if( !GetLines().Count() ) 2238 return; 2239 2240 SwTableLine* pTmpLine = GetLines()[0]->GetLine(); 2241 sal_uInt16 nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine ); 2242 ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" ); 2243 if( nPos ) 2244 pLineBefore = rTable.GetTabLines()[ nPos - 1 ]; 2245 2246 pTmpLine = GetLines()[GetLines().Count()-1]->GetLine(); 2247 nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine ); 2248 ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" ); 2249 if( ++nPos < rTable.GetTabLines().Count() ) 2250 pLineBehind = rTable.GetTabLines()[nPos]; 2251 } 2252 2253 inline void UnsetFollow( SwFlowFrm *pTab ) 2254 { 2255 pTab->bIsFollow = sal_False; 2256 } 2257 2258 void _FndBox::DelFrms( SwTable &rTable ) 2259 { 2260 //Alle Lines zwischen pLineBefore und pLineBehind muessen aus dem 2261 //Layout ausgeschnitten und geloescht werden. 2262 //Entstehen dabei leere Follows so muessen diese vernichtet werden. 2263 //Wird ein Master vernichtet, so muss der Follow Master werden. 2264 //Ein TabFrm muss immer uebrigbleiben. 2265 2266 sal_uInt16 nStPos = 0; 2267 sal_uInt16 nEndPos= rTable.GetTabLines().Count() - 1; 2268 if( rTable.IsNewModel() && pLineBefore ) 2269 rTable.CheckRowSpan( pLineBefore, true ); 2270 if ( pLineBefore ) 2271 { 2272 nStPos = rTable.GetTabLines().GetPos( 2273 (const SwTableLine*&)pLineBefore ); 2274 ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); 2275 ++nStPos; 2276 } 2277 if( rTable.IsNewModel() && pLineBehind ) 2278 rTable.CheckRowSpan( pLineBehind, false ); 2279 if ( pLineBehind ) 2280 { 2281 nEndPos = rTable.GetTabLines().GetPos( 2282 (const SwTableLine*&)pLineBehind ); 2283 ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); 2284 --nEndPos; 2285 } 2286 2287 for ( sal_uInt16 i = nStPos; i <= nEndPos; ++i) 2288 { 2289 SwFrmFmt *pFmt = rTable.GetTabLines()[i]->GetFrmFmt(); 2290 SwIterator<SwRowFrm,SwFmt> aIter( *pFmt ); 2291 for ( SwRowFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() ) 2292 { 2293 if ( pFrm->GetTabLine() == rTable.GetTabLines()[i] ) 2294 { 2295 sal_Bool bDel = sal_True; 2296 SwTabFrm *pUp = !pFrm->GetPrev() && !pFrm->GetNext() ? 2297 (SwTabFrm*)pFrm->GetUpper() : 0; 2298 if ( !pUp ) 2299 { 2300 const sal_uInt16 nRepeat = 2301 ((SwTabFrm*)pFrm->GetUpper())->GetTable()->GetRowsToRepeat(); 2302 if ( nRepeat > 0 && 2303 ((SwTabFrm*)pFrm->GetUpper())->IsFollow() ) 2304 { 2305 if ( !pFrm->GetNext() ) 2306 { 2307 SwRowFrm* pFirstNonHeadline = 2308 ((SwTabFrm*)pFrm->GetUpper())->GetFirstNonHeadlineRow(); 2309 if ( pFirstNonHeadline == pFrm ) 2310 { 2311 pUp = (SwTabFrm*)pFrm->GetUpper(); 2312 } 2313 } 2314 } 2315 } 2316 if ( pUp ) 2317 { 2318 SwTabFrm *pFollow = pUp->GetFollow(); 2319 SwTabFrm *pPrev = pUp->IsFollow() ? pUp : 0; 2320 if ( pPrev ) 2321 { 2322 SwFrm *pTmp = pPrev->FindPrev(); 2323 ASSERT( pTmp->IsTabFrm(), 2324 "Vorgaenger vom Follow kein Master."); 2325 pPrev = (SwTabFrm*)pTmp; 2326 } 2327 if ( pPrev ) 2328 { 2329 pPrev->SetFollow( pFollow ); 2330 // --> FME 2006-01-31 #i60340# Do not transfer the 2331 // flag from pUp to pPrev. pUp may still have the 2332 // flag set although there is not more follow flow 2333 // line associated with pUp. 2334 pPrev->SetFollowFlowLine( sal_False ); 2335 // <-- 2336 } 2337 else if ( pFollow ) 2338 ::UnsetFollow( pFollow ); 2339 2340 //Ein TabellenFrm muss immer stehenbleiben! 2341 if ( pPrev || pFollow ) 2342 { 2343 // OD 26.08.2003 #i18103# - if table is in a section, 2344 // lock the section, to avoid its delete. 2345 { 2346 SwSectionFrm* pSctFrm = pUp->FindSctFrm(); 2347 bool bOldSectLock = false; 2348 if ( pSctFrm ) 2349 { 2350 bOldSectLock = pSctFrm->IsColLocked(); 2351 pSctFrm->ColLock(); 2352 } 2353 pUp->Cut(); 2354 if ( pSctFrm && !bOldSectLock ) 2355 { 2356 pSctFrm->ColUnlock(); 2357 } 2358 } 2359 delete pUp; 2360 bDel = sal_False;//Die Row wird mit in den Abgrund 2361 //gerissen. 2362 } 2363 } 2364 if ( bDel ) 2365 { 2366 SwFrm* pTabFrm = pFrm->GetUpper(); 2367 if ( pTabFrm->IsTabFrm() && 2368 !pFrm->GetNext() && 2369 ((SwTabFrm*)pTabFrm)->GetFollow() ) 2370 { 2371 // We do not delete the follow flow line, 2372 // this will be done automatically in the 2373 // next turn. 2374 ((SwTabFrm*)pTabFrm)->SetFollowFlowLine( sal_False ); 2375 } 2376 2377 pFrm->Cut(); 2378 delete pFrm; 2379 } 2380 } 2381 } 2382 } 2383 } 2384 2385 sal_Bool lcl_IsLineOfTblFrm( const SwTabFrm& rTable, const SwFrm& rChk ) 2386 { 2387 const SwTabFrm* pTblFrm = rChk.FindTabFrm(); 2388 if( pTblFrm->IsFollow() ) 2389 pTblFrm = pTblFrm->FindMaster( true ); 2390 return &rTable == pTblFrm; 2391 } 2392 2393 /* 2394 * lcl_UpdateRepeatedHeadlines 2395 */ 2396 void lcl_UpdateRepeatedHeadlines( SwTabFrm& rTabFrm, bool bCalcLowers ) 2397 { 2398 ASSERT( rTabFrm.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" ) 2399 2400 // Delete remaining headlines: 2401 SwRowFrm* pLower = 0; 2402 while ( 0 != ( pLower = (SwRowFrm*)rTabFrm.Lower() ) && pLower->IsRepeatedHeadline() ) 2403 { 2404 pLower->Cut(); 2405 delete pLower; 2406 } 2407 2408 // Insert fresh set of headlines: 2409 pLower = (SwRowFrm*)rTabFrm.Lower(); 2410 SwTable& rTable = *rTabFrm.GetTable(); 2411 const sal_uInt16 nRepeat = rTable.GetRowsToRepeat(); 2412 for ( sal_uInt16 nIdx = 0; nIdx < nRepeat; ++nIdx ) 2413 { 2414 SwRowFrm* pHeadline = new SwRowFrm( *rTable.GetTabLines()[ nIdx ], &rTabFrm ); 2415 pHeadline->SetRepeatedHeadline( true ); 2416 pHeadline->Paste( &rTabFrm, pLower ); 2417 pHeadline->RegistFlys(); 2418 } 2419 2420 if ( bCalcLowers ) 2421 rTabFrm.SetCalcLowers(); 2422 } 2423 2424 void _FndBox::MakeFrms( SwTable &rTable ) 2425 { 2426 //Alle Lines zwischen pLineBefore und pLineBehind muessen im Layout 2427 //wieder neu erzeugt werden. 2428 //Und Zwar fuer alle Auspraegungen der Tabelle (mehrere z.B. im Kopf/Fuss). 2429 2430 sal_uInt16 nStPos = 0; 2431 sal_uInt16 nEndPos= rTable.GetTabLines().Count() - 1; 2432 if ( pLineBefore ) 2433 { 2434 nStPos = rTable.GetTabLines().GetPos( 2435 (const SwTableLine*&)pLineBefore ); 2436 ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); 2437 ++nStPos; 2438 2439 } 2440 if ( pLineBehind ) 2441 { 2442 nEndPos = rTable.GetTabLines().GetPos( 2443 (const SwTableLine*&)pLineBehind ); 2444 ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); 2445 --nEndPos; 2446 } 2447 //Jetzt die grosse Einfuegeoperation fuer alle Tabllen. 2448 SwIterator<SwTabFrm,SwFmt> aTabIter( *rTable.GetFrmFmt() ); 2449 for ( SwTabFrm *pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() ) 2450 { 2451 if ( !pTable->IsFollow() ) 2452 { 2453 SwRowFrm *pSibling = 0; 2454 SwFrm *pUpperFrm = 0; 2455 int i; 2456 for ( i = rTable.GetTabLines().Count()-1; 2457 i >= 0 && !pSibling; --i ) 2458 { 2459 SwTableLine *pLine = pLineBehind ? pLineBehind : 2460 rTable.GetTabLines()[static_cast<sal_uInt16>(i)]; 2461 SwIterator<SwRowFrm,SwFmt> aIter( *pLine->GetFrmFmt() ); 2462 pSibling = aIter.First(); 2463 while ( pSibling && ( 2464 pSibling->GetTabLine() != pLine || 2465 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) || 2466 pSibling->IsRepeatedHeadline() || 2467 // --> FME 2005-08-24 #i53647# If !pLineBehind, 2468 // IsInSplitTableRow() should be checked. 2469 ( pLineBehind && pSibling->IsInFollowFlowRow() ) || 2470 (!pLineBehind && pSibling->IsInSplitTableRow() ) ) ) 2471 // <-- 2472 { 2473 pSibling = aIter.Next(); 2474 } 2475 } 2476 if ( pSibling ) 2477 { 2478 pUpperFrm = pSibling->GetUpper(); 2479 if ( !pLineBehind ) 2480 pSibling = 0; 2481 } 2482 else 2483 // ???? oder das der Letzte Follow der Tabelle ???? 2484 pUpperFrm = pTable; 2485 2486 for ( i = nStPos; (sal_uInt16)i <= nEndPos; ++i ) 2487 ::lcl_InsertRow( *rTable.GetTabLines()[static_cast<sal_uInt16>(i)], 2488 (SwLayoutFrm*)pUpperFrm, pSibling ); 2489 if ( pUpperFrm->IsTabFrm() ) 2490 ((SwTabFrm*)pUpperFrm)->SetCalcLowers(); 2491 } 2492 else if ( rTable.GetRowsToRepeat() > 0 ) 2493 { 2494 // Insert new headlines: 2495 lcl_UpdateRepeatedHeadlines( *pTable, true ); 2496 } 2497 } 2498 } 2499 2500 void _FndBox::MakeNewFrms( SwTable &rTable, const sal_uInt16 nNumber, 2501 const sal_Bool bBehind ) 2502 { 2503 //Frms fuer neu eingefuege Zeilen erzeugen. 2504 //bBehind == sal_True: vor pLineBehind 2505 // == sal_False: hinter pLineBefore 2506 const sal_uInt16 nBfPos = pLineBefore ? 2507 rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBefore ) : 2508 USHRT_MAX; 2509 const sal_uInt16 nBhPos = pLineBehind ? 2510 rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBehind ) : 2511 USHRT_MAX; 2512 2513 //nNumber: wie oft ist eingefuegt worden. 2514 //nCnt: wieviele sind nNumber mal eingefuegt worden. 2515 2516 const sal_uInt16 nCnt = 2517 ((nBhPos != USHRT_MAX ? nBhPos : rTable.GetTabLines().Count()) - 2518 (nBfPos != USHRT_MAX ? nBfPos + 1 : 0)) / (nNumber + 1); 2519 2520 //Den Master-TabFrm suchen 2521 SwIterator<SwTabFrm,SwFmt> aTabIter( *rTable.GetFrmFmt() ); 2522 SwTabFrm *pTable; 2523 for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() ) 2524 { 2525 if( !pTable->IsFollow() ) 2526 { 2527 SwRowFrm* pSibling = 0; 2528 SwLayoutFrm *pUpperFrm = 0; 2529 if ( bBehind ) 2530 { 2531 if ( pLineBehind ) 2532 { 2533 SwIterator<SwRowFrm,SwFmt> aIter( *pLineBehind->GetFrmFmt() ); 2534 pSibling = aIter.First(); 2535 while ( pSibling && ( 2536 // only consider row frames associated with pLineBehind: 2537 pSibling->GetTabLine() != pLineBehind || 2538 // only consider row frames that are in pTables Master-Follow chain: 2539 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) || 2540 // only consider row frames that are not repeated headlines: 2541 pSibling->IsRepeatedHeadline() || 2542 // only consider row frames that are not follow flow rows 2543 pSibling->IsInFollowFlowRow() ) ) 2544 { 2545 pSibling = aIter.Next(); 2546 } 2547 } 2548 if ( pSibling ) 2549 pUpperFrm = pSibling->GetUpper(); 2550 else 2551 { 2552 while( pTable->GetFollow() ) 2553 pTable = pTable->GetFollow(); 2554 pUpperFrm = pTable; 2555 } 2556 const sal_uInt16 nMax = nBhPos != USHRT_MAX ? 2557 nBhPos : rTable.GetTabLines().Count(); 2558 2559 sal_uInt16 i = nBfPos != USHRT_MAX ? nBfPos + 1 + nCnt : nCnt; 2560 2561 for ( ; i < nMax; ++i ) 2562 ::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrm, pSibling ); 2563 if ( pUpperFrm->IsTabFrm() ) 2564 ((SwTabFrm*)pUpperFrm)->SetCalcLowers(); 2565 } 2566 else //davor einfuegen 2567 { 2568 sal_uInt16 i; 2569 2570 // We are looking for the frame that is behind the row frame 2571 // that should be inserted. 2572 for ( i = 0; !pSibling; ++i ) 2573 { 2574 SwTableLine* pLine = pLineBefore ? pLineBefore : rTable.GetTabLines()[i]; 2575 2576 SwIterator<SwRowFrm,SwFmt> aIter( *pLine->GetFrmFmt() ); 2577 pSibling = aIter.First(); 2578 2579 while ( pSibling && ( 2580 // only consider row frames associated with pLineBefore: 2581 pSibling->GetTabLine() != pLine || 2582 // only consider row frames that are in pTables Master-Follow chain: 2583 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) || 2584 // only consider row frames that are not repeated headlines: 2585 pSibling->IsRepeatedHeadline() || 2586 // 1. case: pLineBefore == 0: 2587 // only consider row frames that are not follow flow rows 2588 // 2. case: pLineBefore != 0: 2589 // only consider row frames that are not split table rows 2590 // --> FME 2004-11-23 #i37476# If !pLineBefore, 2591 // check IsInFollowFlowRow instead of IsInSplitTableRow. 2592 ( ( !pLineBefore && pSibling->IsInFollowFlowRow() ) || 2593 ( pLineBefore && pSibling->IsInSplitTableRow() ) ) ) ) 2594 // <-- 2595 { 2596 pSibling = aIter.Next(); 2597 } 2598 } 2599 2600 pUpperFrm = pSibling->GetUpper(); 2601 if ( pLineBefore ) 2602 pSibling = (SwRowFrm*) pSibling->GetNext(); 2603 2604 sal_uInt16 nMax = nBhPos != USHRT_MAX ? 2605 nBhPos - nCnt : 2606 rTable.GetTabLines().Count() - nCnt; 2607 2608 i = nBfPos != USHRT_MAX ? nBfPos + 1 : 0; 2609 for ( ; i < nMax; ++i ) 2610 ::lcl_InsertRow( *rTable.GetTabLines()[i], 2611 pUpperFrm, pSibling ); 2612 if ( pUpperFrm->IsTabFrm() ) 2613 ((SwTabFrm*)pUpperFrm)->SetCalcLowers(); 2614 } 2615 } 2616 } 2617 2618 //Die Headlines mussen ggf. auch verarbeitet werden. Um gut arbeitenden 2619 //Code nicht zu zerfasern wird hier nochmals iteriert. 2620 const sal_uInt16 nRowsToRepeat = rTable.GetRowsToRepeat(); 2621 if ( nRowsToRepeat > 0 && 2622 ( ( !bBehind && ( nBfPos == USHRT_MAX || nBfPos + 1 < nRowsToRepeat ) ) || 2623 ( bBehind && ( ( nBfPos == USHRT_MAX && nRowsToRepeat > 1 ) || nBfPos + 2 < nRowsToRepeat ) ) ) ) 2624 { 2625 for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() ) 2626 { 2627 if ( pTable->Lower() ) 2628 { 2629 if ( pTable->IsFollow() ) 2630 { 2631 lcl_UpdateRepeatedHeadlines( *pTable, true ); 2632 } 2633 2634 ASSERT( ((SwRowFrm*)pTable->Lower())->GetTabLine() == 2635 rTable.GetTabLines()[0], "MakeNewFrms: Table corruption!" ) 2636 } 2637 } 2638 } 2639 } 2640 2641 sal_Bool _FndBox::AreLinesToRestore( const SwTable &rTable ) const 2642 { 2643 //Lohnt es sich MakeFrms zu rufen? 2644 2645 if ( !pLineBefore && !pLineBehind && rTable.GetTabLines().Count() ) 2646 return sal_True; 2647 2648 sal_uInt16 nBfPos; 2649 if(pLineBefore) 2650 { 2651 const SwTableLine* rLBefore = (const SwTableLine*)pLineBefore; 2652 nBfPos = rTable.GetTabLines().GetPos( rLBefore ); 2653 } 2654 else 2655 nBfPos = USHRT_MAX; 2656 2657 sal_uInt16 nBhPos; 2658 if(pLineBehind) 2659 { 2660 const SwTableLine* rLBehind = (const SwTableLine*)pLineBehind; 2661 nBhPos = rTable.GetTabLines().GetPos( rLBehind ); 2662 } 2663 else 2664 nBhPos = USHRT_MAX; 2665 2666 if ( nBfPos == nBhPos ) //Duerfte eigentlich nie vorkommen. 2667 { 2668 ASSERT( sal_False, "Table, Loeschen auf keinem Bereich !?!" ); 2669 return sal_False; 2670 } 2671 2672 if ( rTable.GetRowsToRepeat() > 0 ) 2673 { 2674 // ups. sollte unsere zu wiederholende Kopfzeile geloescht worden 2675 // sein?? 2676 SwIterator<SwTabFrm,SwFmt> aIter( *rTable.GetFrmFmt() ); 2677 for( SwTabFrm* pTable = aIter.First(); pTable; pTable = aIter.Next() ) 2678 { 2679 if( pTable->IsFollow() ) 2680 { 2681 // Insert new headlines: 2682 lcl_UpdateRepeatedHeadlines( *pTable, false ); 2683 } 2684 } 2685 } 2686 2687 // Some adjacent lines at the beginning of the table have been deleted: 2688 if ( nBfPos == USHRT_MAX && nBhPos == 0 ) 2689 return sal_False; 2690 2691 // Some adjacent lines at the end of the table have been deleted: 2692 if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().Count() - 1) ) 2693 return sal_False; 2694 2695 // Some adjacent lines in the middle of the table have been deleted: 2696 if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos ) 2697 return sal_False; 2698 2699 // The structure of the deleted lines is more complex due to split lines. 2700 // A call of MakeFrms() is necessary. 2701 return sal_True; 2702 } 2703 2704 2705