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