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, nCellCnt = 0; 644 long nYPos = LONG_MAX; 645 long nXPos = 0; 646 long nHeight = 0; 647 648 for( n = 0 ; n < aCellFrms.size(); ++n ) 649 { 650 const _Sort_CellFrm& rCF = aCellFrms[ n ]; 651 if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos ) 652 { 653 // neue Zeile 654 if( n ) 655 { 656 if( USHRT_MAX == nRowCells ) // 1. Zeilenwechsel 657 nRowCells = nCellCnt; 658 else if( nRowCells != nCellCnt ) 659 { 660 bValidChartSel = sal_False; 661 break; 662 } 663 } 664 nCellCnt = 1; 665 nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)(); 666 nHeight = (rCF.pFrm->Frm().*fnRect->fnGetHeight)(); 667 668 nXPos = bRTL ? 669 (rCF.pFrm->Frm().*fnRect->fnGetLeft)() : 670 (rCF.pFrm->Frm().*fnRect->fnGetRight)(); 671 } 672 else if( nXPos == ( bRTL ? 673 (rCF.pFrm->Frm().*fnRect->fnGetRight)() : 674 (rCF.pFrm->Frm().*fnRect->fnGetLeft)() ) && 675 nHeight == (rCF.pFrm->Frm().*fnRect->fnGetHeight)() ) 676 { 677 nXPos += ( bRTL ? (-1) : 1 ) * 678 (rCF.pFrm->Frm().*fnRect->fnGetWidth)(); 679 ++nCellCnt; 680 } 681 else 682 { 683 bValidChartSel = sal_False; 684 break; 685 } 686 } 687 if( bValidChartSel ) 688 { 689 if( USHRT_MAX == nRowCells ) 690 nRowCells = nCellCnt; 691 else if( nRowCells != nCellCnt ) 692 bValidChartSel = sal_False; 693 } 694 695 if( bValidChartSel && pGetCLines ) 696 { 697 nYPos = LONG_MAX; 698 SwChartBoxes* pBoxes = 0; 699 for( n = 0; n < aCellFrms.size(); ++n ) 700 { 701 const _Sort_CellFrm& rCF = aCellFrms[ n ]; 702 if( (rCF.pFrm->Frm().*fnRect->fnGetTop)() != nYPos ) 703 { 704 pBoxes = new SwChartBoxes( 255 < nRowCells 705 ? 255 : (sal_uInt8)nRowCells); 706 pGetCLines->C40_INSERT( SwChartBoxes, pBoxes, pGetCLines->Count() ); 707 nYPos = (rCF.pFrm->Frm().*fnRect->fnGetTop)(); 708 } 709 SwTableBoxPtr pBox = (SwTableBox*)rCF.pFrm->GetTabBox(); 710 pBoxes->Insert( pBox, pBoxes->Count() ); 711 } 712 } 713 } 714 715 if( bTblIsValid ) 716 break; 717 718 // ansonsten das Layout der Tabelle kurz "kalkulieren" lassen 719 // und nochmals neu aufsetzen 720 SwTabFrm *pTable = aUnions[0]->GetTable(); 721 for( i = 0; i < aUnions.Count(); ++i ) 722 { 723 if( pTable->IsValid() ) 724 pTable->InvalidatePos(); 725 pTable->SetONECalcLowers(); 726 pTable->Calc(); 727 pTable->SetCompletePaint(); 728 if( 0 == (pTable = pTable->GetFollow()) ) 729 break; 730 } 731 --nLoopMax; 732 if( pGetCLines ) 733 pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() ); 734 } while( sal_True ); 735 736 ASSERT( nLoopMax, "das Layout der Tabelle wurde nicht valide!" ); 737 738 if( !bValidChartSel && pGetCLines ) 739 pGetCLines->DeleteAndDestroy( 0, pGetCLines->Count() ); 740 741 return bValidChartSel; 742 } 743 744 745 sal_Bool IsFrmInTblSel( const SwRect& rUnion, const SwFrm* pCell ) 746 { 747 ASSERT( pCell->IsCellFrm(), "Frame ohne Gazelle" ); 748 749 if( pCell->FindTabFrm()->IsVertical() ) 750 return ( rUnion.Right() >= pCell->Frm().Right() && 751 rUnion.Left() <= pCell->Frm().Left() && 752 (( rUnion.Top() <= pCell->Frm().Top()+20 && 753 rUnion.Bottom() > pCell->Frm().Top() ) || 754 ( rUnion.Top() >= pCell->Frm().Top() && 755 rUnion.Bottom() < pCell->Frm().Bottom() )) ? sal_True : sal_False ); 756 757 return ( 758 rUnion.Top() <= pCell->Frm().Top() && 759 rUnion.Bottom() >= pCell->Frm().Bottom() && 760 761 (( rUnion.Left() <= pCell->Frm().Left()+20 && 762 rUnion.Right() > pCell->Frm().Left() ) || 763 764 ( rUnion.Left() >= pCell->Frm().Left() && 765 rUnion.Right() < pCell->Frm().Right() )) ? sal_True : sal_False ); 766 } 767 768 sal_Bool GetAutoSumSel( const SwCrsrShell& rShell, SwCellFrms& rBoxes ) 769 { 770 SwShellCrsr* pCrsr = rShell.pCurCrsr; 771 if ( rShell.IsTableMode() ) 772 pCrsr = rShell.pTblCrsr; 773 774 const SwLayoutFrm *pStart = pCrsr->GetCntntNode()->getLayoutFrm( rShell.GetLayout(), 775 &pCrsr->GetPtPos() )->GetUpper(), 776 *pEnd = pCrsr->GetCntntNode(sal_False)->getLayoutFrm( rShell.GetLayout(), 777 &pCrsr->GetMkPos() )->GetUpper(); 778 779 const SwLayoutFrm* pSttCell = pStart; 780 while( pSttCell && !pSttCell->IsCellFrm() ) 781 pSttCell = pSttCell->GetUpper(); 782 783 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. 784 SwSelUnions aUnions; 785 786 // default erstmal nach oben testen, dann nach links 787 ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_COL ); 788 789 sal_Bool bTstRow = sal_True, bFound = sal_False; 790 sal_uInt16 i; 791 792 // 1. teste ob die darueber liegende Box Value/Formel enhaelt: 793 for( i = 0; i < aUnions.Count(); ++i ) 794 { 795 SwSelUnion *pUnion = aUnions[i]; 796 const SwTabFrm *pTable = pUnion->GetTable(); 797 798 // Skip any repeated headlines in the follow: 799 const SwLayoutFrm* pRow = pTable->IsFollow() ? 800 pTable->GetFirstNonHeadlineRow() : 801 (const SwLayoutFrm*)pTable->Lower(); 802 803 while( pRow ) 804 { 805 if( pRow->Frm().IsOver( pUnion->GetUnion() ) ) 806 { 807 const SwCellFrm* pUpperCell = 0; 808 const SwLayoutFrm *pCell = pRow->FirstCell(); 809 810 while( pCell && pRow->IsAnLower( pCell ) ) 811 { 812 if( pCell == pSttCell ) 813 { 814 sal_uInt16 nWhichId = 0; 815 for( sal_uInt16 n = rBoxes.Count(); n; ) 816 if( USHRT_MAX != ( nWhichId = rBoxes[ --n ] 817 ->GetTabBox()->IsFormulaOrValueBox() )) 818 break; 819 820 // alle Boxen zusammen, nicht mehr die Zeile 821 // pruefen, wenn eine Formel oder Value gefunden wurde 822 bTstRow = 0 == nWhichId || USHRT_MAX == nWhichId; 823 bFound = sal_True; 824 break; 825 } 826 827 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); 828 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) 829 pUpperCell = (SwCellFrm*)pCell; 830 831 if( pCell->GetNext() ) 832 { 833 pCell = (const SwLayoutFrm*)pCell->GetNext(); 834 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) 835 pCell = pCell->FirstCell(); 836 } 837 else 838 pCell = ::lcl_FindNextCellFrm( pCell ); 839 } 840 841 if( pUpperCell ) 842 rBoxes.Insert( pUpperCell, rBoxes.Count() ); 843 } 844 if( bFound ) 845 { 846 i = aUnions.Count(); 847 break; 848 } 849 pRow = (const SwLayoutFrm*)pRow->GetNext(); 850 } 851 } 852 853 854 // 2. teste ob die links liegende Box Value/Formel enhaelt: 855 if( bTstRow ) 856 { 857 bFound = sal_False; 858 859 rBoxes.Remove( 0, rBoxes.Count() ); 860 aUnions.DeleteAndDestroy( 0, aUnions.Count() ); 861 ::MakeSelUnions( aUnions, pStart, pEnd, nsSwTblSearchType::TBLSEARCH_ROW ); 862 863 for( i = 0; i < aUnions.Count(); ++i ) 864 { 865 SwSelUnion *pUnion = aUnions[i]; 866 const SwTabFrm *pTable = pUnion->GetTable(); 867 868 // Skip any repeated headlines in the follow: 869 const SwLayoutFrm* pRow = pTable->IsFollow() ? 870 pTable->GetFirstNonHeadlineRow() : 871 (const SwLayoutFrm*)pTable->Lower(); 872 873 while( pRow ) 874 { 875 if( pRow->Frm().IsOver( pUnion->GetUnion() ) ) 876 { 877 const SwLayoutFrm *pCell = pRow->FirstCell(); 878 879 while( pCell && pRow->IsAnLower( pCell ) ) 880 { 881 if( pCell == pSttCell ) 882 { 883 sal_uInt16 nWhichId = 0; 884 for( sal_uInt16 n = rBoxes.Count(); n; ) 885 if( USHRT_MAX != ( nWhichId = rBoxes[ --n ] 886 ->GetTabBox()->IsFormulaOrValueBox() )) 887 break; 888 889 // alle Boxen zusammen, nicht mehr die Zeile 890 // pruefen, wenn eine Formel oder Value gefunden wurde 891 bFound = 0 != nWhichId && USHRT_MAX != nWhichId; 892 bTstRow = sal_False; 893 break; 894 } 895 896 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); 897 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) 898 { 899 const SwCellFrm* pC = (SwCellFrm*)pCell; 900 rBoxes.Insert( pC, rBoxes.Count() ); 901 } 902 if( pCell->GetNext() ) 903 { 904 pCell = (const SwLayoutFrm*)pCell->GetNext(); 905 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) 906 pCell = pCell->FirstCell(); 907 } 908 else 909 pCell = ::lcl_FindNextCellFrm( pCell ); 910 } 911 } 912 if( !bTstRow ) 913 { 914 i = aUnions.Count(); 915 break; 916 } 917 918 pRow = (const SwLayoutFrm*)pRow->GetNext(); 919 } 920 } 921 } 922 923 return bFound; 924 } 925 926 sal_Bool HasProtectedCells( const SwSelBoxes& rBoxes ) 927 { 928 sal_Bool bRet = sal_False; 929 for( sal_uInt16 n = 0, nCnt = rBoxes.Count(); n < nCnt; ++n ) 930 if( rBoxes[ n ]->GetFrmFmt()->GetProtect().IsCntntProtected() ) 931 { 932 bRet = sal_True; 933 break; 934 } 935 return bRet; 936 } 937 938 939 _CmpLPt::_CmpLPt( const Point& rPt, const SwTableBox* pBox, sal_Bool bVertical ) 940 : aPos( rPt ), pSelBox( pBox ), bVert( bVertical ) 941 {} 942 943 void lcl_InsTblBox( SwTableNode* pTblNd, SwDoc* pDoc, SwTableBox* pBox, 944 sal_uInt16 nInsPos, sal_uInt16 nCnt = 1 ) 945 { 946 ASSERT( pBox->GetSttNd(), "Box ohne Start-Node" ); 947 SwCntntNode* pCNd = pDoc->GetNodes()[ pBox->GetSttIdx() + 1 ] 948 ->GetCntntNode(); 949 if( pCNd && pCNd->IsTxtNode() ) 950 pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(), 951 (SwTableBoxFmt*)pBox->GetFrmFmt(), 952 ((SwTxtNode*)pCNd)->GetTxtColl(), 953 pCNd->GetpSwAttrSet(), 954 nInsPos, nCnt ); 955 else 956 pDoc->GetNodes().InsBoxen( pTblNd, pBox->GetUpper(), 957 (SwTableBoxFmt*)pBox->GetFrmFmt(), 958 (SwTxtFmtColl*)pDoc->GetDfltTxtFmtColl(), 0, 959 nInsPos, nCnt ); 960 } 961 962 sal_Bool IsEmptyBox( const SwTableBox& rBox, SwPaM& rPam ) 963 { 964 rPam.GetPoint()->nNode = *rBox.GetSttNd()->EndOfSectionNode(); 965 rPam.Move( fnMoveBackward, fnGoCntnt ); 966 rPam.SetMark(); 967 rPam.GetPoint()->nNode = *rBox.GetSttNd(); 968 rPam.Move( fnMoveForward, fnGoCntnt ); 969 sal_Bool bRet = *rPam.GetMark() == *rPam.GetPoint() 970 && ( rBox.GetSttNd()->GetIndex() + 1 == rPam.GetPoint()->nNode.GetIndex() ); 971 972 if( bRet ) 973 { 974 // dann teste mal auf absatzgebundenen Flys 975 const SwSpzFrmFmts& rFmts = *rPam.GetDoc()->GetSpzFrmFmts(); 976 sal_uLong nSttIdx = rPam.GetPoint()->nNode.GetIndex(), 977 nEndIdx = rBox.GetSttNd()->EndOfSectionIndex(), 978 nIdx; 979 980 for( sal_uInt16 n = 0; n < rFmts.Count(); ++n ) 981 { 982 const SwFmtAnchor& rAnchor = rFmts[n]->GetAnchor(); 983 const SwPosition* pAPos = rAnchor.GetCntntAnchor(); 984 if (pAPos && 985 ((FLY_AT_PARA == rAnchor.GetAnchorId()) || 986 (FLY_AT_CHAR == rAnchor.GetAnchorId())) && 987 nSttIdx <= ( nIdx = pAPos->nNode.GetIndex() ) && 988 nIdx < nEndIdx ) 989 { 990 bRet = sal_False; 991 break; 992 } 993 } 994 } 995 return bRet; 996 } 997 998 999 void GetMergeSel( const SwPaM& rPam, SwSelBoxes& rBoxes, 1000 SwTableBox** ppMergeBox, SwUndoTblMerge* pUndo ) 1001 { 1002 if( rBoxes.Count() ) 1003 rBoxes.Remove( sal_uInt16(0), rBoxes.Count() ); 1004 1005 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. 1006 ASSERT( rPam.GetCntntNode() && rPam.GetCntntNode( sal_False ), 1007 "Tabselection nicht auf Cnt." ); 1008 1009 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht 1010 // richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert, 1011 // das die 1. Headline mit drin ist. 1012 // Point aPt( rShell.GetCharRect().Pos() ); 1013 Point aPt( 0, 0 ); 1014 1015 const SwCntntNode* pCntNd = rPam.GetCntntNode(); 1016 const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 1017 &aPt )->GetUpper(); 1018 pCntNd = rPam.GetCntntNode(sal_False); 1019 const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 1020 &aPt )->GetUpper(); 1021 1022 SwSelUnions aUnions; 1023 ::MakeSelUnions( aUnions, pStart, pEnd ); 1024 if( !aUnions.Count() ) 1025 return; 1026 1027 const SwTable *pTable = aUnions[0]->GetTable()->GetTable(); 1028 SwDoc* pDoc = (SwDoc*)pStart->GetFmt()->GetDoc(); 1029 SwTableNode* pTblNd = (SwTableNode*)pTable->GetTabSortBoxes()[ 0 ]-> 1030 GetSttNd()->FindTableNode(); 1031 1032 _MergePos aPosArr; // Sort-Array mit den Positionen der Frames 1033 long nWidth; 1034 SwTableBox* pLastBox = 0; 1035 1036 SWRECTFN( pStart->GetUpper() ) 1037 1038 for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) 1039 { 1040 const SwTabFrm *pTabFrm = aUnions[i]->GetTable(); 1041 1042 SwRect &rUnion = aUnions[i]->GetUnion(); 1043 1044 // Skip any repeated headlines in the follow: 1045 const SwLayoutFrm* pRow = pTabFrm->IsFollow() ? 1046 pTabFrm->GetFirstNonHeadlineRow() : 1047 (const SwLayoutFrm*)pTabFrm->Lower(); 1048 1049 while ( pRow ) 1050 { 1051 if ( pRow->Frm().IsOver( rUnion ) ) 1052 { 1053 const SwLayoutFrm *pCell = pRow->FirstCell(); 1054 1055 while ( pCell && pRow->IsAnLower( pCell ) ) 1056 { 1057 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); 1058 // in der vollen Breite ueberlappend ? 1059 if( rUnion.Top() <= pCell->Frm().Top() && 1060 rUnion.Bottom() >= pCell->Frm().Bottom() ) 1061 { 1062 SwTableBox* pBox =(SwTableBox*)((SwCellFrm*)pCell)->GetTabBox(); 1063 1064 // nur nach rechts ueberlappend 1065 if( ( rUnion.Left() - COLFUZZY ) <= pCell->Frm().Left() && 1066 ( rUnion.Right() - COLFUZZY ) > pCell->Frm().Left() ) 1067 { 1068 if( ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() ) 1069 { 1070 sal_uInt16 nInsPos = pBox->GetUpper()-> 1071 GetTabBoxes().C40_GETPOS( SwTableBox, pBox )+1; 1072 lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos ); 1073 pBox->ClaimFrmFmt(); 1074 SwFmtFrmSize aNew( 1075 pBox->GetFrmFmt()->GetFrmSize() ); 1076 nWidth = rUnion.Right() - pCell->Frm().Left(); 1077 nWidth = nWidth * aNew.GetWidth() / 1078 pCell->Frm().Width(); 1079 long nTmpWidth = aNew.GetWidth() - nWidth; 1080 aNew.SetWidth( nWidth ); 1081 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1082 // diese Box ist selektiert 1083 pLastBox = pBox; 1084 rBoxes.Insert( pBox ); 1085 aPosArr.Insert( 1086 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(), 1087 pBox, bVert ) ); 1088 1089 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ]; 1090 aNew.SetWidth( nTmpWidth ); 1091 pBox->ClaimFrmFmt(); 1092 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1093 1094 if( pUndo ) 1095 pUndo->AddNewBox( pBox->GetSttIdx() ); 1096 } 1097 else 1098 { 1099 // diese Box ist selektiert 1100 pLastBox = pBox; 1101 rBoxes.Insert( pBox ); 1102 #if OSL_DEBUG_LEVEL > 1 1103 Point aInsPoint( (pCell->Frm().*fnRect->fnGetPos)() ); 1104 #endif 1105 aPosArr.Insert( 1106 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(), 1107 pBox, bVert ) ); 1108 } 1109 } 1110 // oder rechts und links ueberlappend 1111 else if( ( rUnion.Left() - COLFUZZY ) >= pCell->Frm().Left() && 1112 ( rUnion.Right() + COLFUZZY ) < pCell->Frm().Right() ) 1113 { 1114 sal_uInt16 nInsPos = pBox->GetUpper()->GetTabBoxes(). 1115 C40_GETPOS( SwTableBox, pBox )+1; 1116 lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 2 ); 1117 pBox->ClaimFrmFmt(); 1118 SwFmtFrmSize aNew( 1119 pBox->GetFrmFmt()->GetFrmSize() ); 1120 long nLeft = rUnion.Left() - pCell->Frm().Left(); 1121 nLeft = nLeft * aNew.GetWidth() / 1122 pCell->Frm().Width(); 1123 long nRight = pCell->Frm().Right() - rUnion.Right(); 1124 nRight = nRight * aNew.GetWidth() / 1125 pCell->Frm().Width(); 1126 nWidth = aNew.GetWidth() - nLeft - nRight; 1127 1128 aNew.SetWidth( nLeft ); 1129 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1130 1131 { 1132 const SfxPoolItem* pItem; 1133 if( SFX_ITEM_SET == pBox->GetFrmFmt()->GetAttrSet() 1134 .GetItemState( RES_BOX, sal_False, &pItem )) 1135 { 1136 SvxBoxItem aBox( *(SvxBoxItem*)pItem ); 1137 aBox.SetLine( 0, BOX_LINE_RIGHT ); 1138 pBox->GetFrmFmt()->SetFmtAttr( aBox ); 1139 } 1140 } 1141 1142 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ]; 1143 aNew.SetWidth( nWidth ); 1144 pBox->ClaimFrmFmt(); 1145 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1146 1147 if( pUndo ) 1148 pUndo->AddNewBox( pBox->GetSttIdx() ); 1149 1150 // diese Box ist selektiert 1151 pLastBox = pBox; 1152 rBoxes.Insert( pBox ); 1153 aPosArr.Insert( 1154 _CmpLPt( (pCell->Frm().*fnRect->fnGetPos)(), 1155 pBox, bVert ) ); 1156 1157 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos+1 ]; 1158 aNew.SetWidth( nRight ); 1159 pBox->ClaimFrmFmt(); 1160 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1161 1162 if( pUndo ) 1163 pUndo->AddNewBox( pBox->GetSttIdx() ); 1164 } 1165 // oder reicht die rechte Kante der Box in den 1166 // selektierten Bereich? 1167 else if( ( pCell->Frm().Right() - COLFUZZY ) < rUnion.Right() && 1168 ( pCell->Frm().Right() - COLFUZZY ) > rUnion.Left() && 1169 ( pCell->Frm().Left() + COLFUZZY ) < rUnion.Left() ) 1170 { 1171 // dann muss eine neue Box einfuegt und die 1172 // Breiten angepasst werden 1173 sal_uInt16 nInsPos = pBox->GetUpper()->GetTabBoxes(). 1174 C40_GETPOS( SwTableBox, pBox )+1; 1175 lcl_InsTblBox( pTblNd, pDoc, pBox, nInsPos, 1 ); 1176 1177 SwFmtFrmSize aNew(pBox->GetFrmFmt()->GetFrmSize() ); 1178 long nLeft = rUnion.Left() - pCell->Frm().Left(), 1179 nRight = pCell->Frm().Right() - rUnion.Left(); 1180 1181 nLeft = nLeft * aNew.GetWidth() / 1182 pCell->Frm().Width(); 1183 nRight = nRight * aNew.GetWidth() / 1184 pCell->Frm().Width(); 1185 1186 aNew.SetWidth( nLeft ); 1187 pBox->ClaimFrmFmt()->SetFmtAttr( aNew ); 1188 1189 // diese Box ist selektiert 1190 pBox = pBox->GetUpper()->GetTabBoxes()[ nInsPos ]; 1191 aNew.SetWidth( nRight ); 1192 pBox->ClaimFrmFmt(); 1193 pBox->GetFrmFmt()->SetFmtAttr( aNew ); 1194 1195 pLastBox = pBox; 1196 rBoxes.Insert( pBox ); 1197 aPosArr.Insert( _CmpLPt( Point( rUnion.Left(), 1198 pCell->Frm().Top()), pBox, bVert )); 1199 1200 if( pUndo ) 1201 pUndo->AddNewBox( pBox->GetSttIdx() ); 1202 } 1203 } 1204 if ( pCell->GetNext() ) 1205 { 1206 pCell = (const SwLayoutFrm*)pCell->GetNext(); 1207 // --> FME 2005-11-03 #125288# Check if table cell is not empty 1208 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) 1209 pCell = pCell->FirstCell(); 1210 } 1211 else 1212 pCell = ::lcl_FindNextCellFrm( pCell ); 1213 } 1214 } 1215 pRow = (const SwLayoutFrm*)pRow->GetNext(); 1216 } 1217 } 1218 1219 // keine SSelection / keine gefundenen Boxen 1220 if( 1 >= rBoxes.Count() ) 1221 return; 1222 1223 // dann suche mal alle Boxen, die nebeneinander liegen, und verbinde 1224 // deren Inhalte mit Blanks. Alle untereinander liegende werden als 1225 // Absaetze zusammengefasst 1226 1227 // 1. Loesung: gehe ueber das Array und 1228 // alle auf der gleichen Y-Ebene werden mit Blanks getrennt 1229 // alle anderen werden als Absaetze getrennt. 1230 sal_Bool bCalcWidth = sal_True; 1231 const SwTableBox* pFirstBox = aPosArr[ 0 ].pSelBox; 1232 1233 // JP 27.03.98: Optimierung - falls die Boxen einer Line leer sind, 1234 // dann werden jetzt dafuer keine Blanks und 1235 // kein Umbruch mehr eingefuegt. 1236 //Block damit SwPaM, SwPosition vom Stack geloescht werden 1237 { 1238 SwPaM aPam( pDoc->GetNodes() ); 1239 1240 #if defined( DEL_ONLY_EMPTY_LINES ) 1241 nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth(); 1242 sal_Bool bEmptyLine = sal_True; 1243 sal_uInt16 n, nSttPos = 0; 1244 1245 for( n = 0; n < aPosArr.Count(); ++n ) 1246 { 1247 const _CmpLPt& rPt = aPosArr[ n ]; 1248 if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // gleiche Ebene ? 1249 { 1250 if( bEmptyLine && !IsEmptyBox( *rPt.pSelBox, aPam )) 1251 bEmptyLine = sal_False; 1252 if( bCalcWidth ) 1253 nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth(); 1254 } 1255 else 1256 { 1257 if( bCalcWidth && n ) 1258 bCalcWidth = sal_False; // eine Zeile fertig 1259 1260 if( bEmptyLine && nSttPos < n ) 1261 { 1262 // dann ist die gesamte Line leer und braucht 1263 // nicht mit Blanks aufgefuellt und als Absatz 1264 // eingefuegt werden. 1265 if( pUndo ) 1266 for( sal_uInt16 i = nSttPos; i < n; ++i ) 1267 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1268 1269 aPosArr.Remove( nSttPos, n - nSttPos ); 1270 n = nSttPos; 1271 } 1272 else 1273 nSttPos = n; 1274 1275 bEmptyLine = IsEmptyBox( *aPosArr[n].pSelBox, aPam ); 1276 } 1277 } 1278 if( bEmptyLine && nSttPos < n ) 1279 { 1280 if( pUndo ) 1281 for( sal_uInt16 i = nSttPos; i < n; ++i ) 1282 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1283 aPosArr.Remove( nSttPos, n - nSttPos ); 1284 } 1285 #elsif defined( DEL_EMPTY_BOXES_AT_START_AND_END ) 1286 1287 nWidth = pFirstBox->GetFrmFmt()->GetFrmSize().GetWidth(); 1288 sal_uInt16 n, nSttPos = 0, nSEndPos = 0, nESttPos = 0; 1289 1290 for( n = 0; n < aPosArr.Count(); ++n ) 1291 { 1292 const _CmpLPt& rPt = aPosArr[ n ]; 1293 if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // gleiche Ebene ? 1294 { 1295 sal_Bool bEmptyBox = IsEmptyBox( *rPt.pSelBox, aPam ); 1296 if( bEmptyBox ) 1297 { 1298 if( nSEndPos == n ) // der Anfang ist leer 1299 nESttPos = ++nSEndPos; 1300 } 1301 else // das Ende kann leer sein 1302 nESttPos = n+1; 1303 1304 if( bCalcWidth ) 1305 nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth(); 1306 } 1307 else 1308 { 1309 if( bCalcWidth && n ) 1310 bCalcWidth = sal_False; // eine Zeile fertig 1311 1312 // zuerst die vom Anfang 1313 if( nSttPos < nSEndPos ) 1314 { 1315 // dann ist der vorder Teil der Line leer und braucht 1316 // nicht mit Blanks aufgefuellt werden. 1317 if( pUndo ) 1318 for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i ) 1319 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1320 1321 sal_uInt16 nCnt = nSEndPos - nSttPos; 1322 aPosArr.Remove( nSttPos, nCnt ); 1323 nESttPos -= nCnt; 1324 n -= nCnt; 1325 } 1326 1327 if( nESttPos < n ) 1328 { 1329 // dann ist der vorder Teil der Line leer und braucht 1330 // nicht mit Blanks aufgefuellt werden. 1331 if( pUndo ) 1332 for( sal_uInt16 i = nESttPos; i < n; ++i ) 1333 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1334 1335 sal_uInt16 nCnt = n - nESttPos; 1336 aPosArr.Remove( nESttPos, nCnt ); 1337 n -= nCnt; 1338 } 1339 1340 nSttPos = nSEndPos = nESttPos = n; 1341 if( IsEmptyBox( *aPosArr[n].pSelBox, aPam )) 1342 ++nSEndPos; 1343 else 1344 ++nESttPos; 1345 } 1346 } 1347 1348 // zuerst die vom Anfang 1349 if( nSttPos < nSEndPos ) 1350 { 1351 // dann ist der vorder Teil der Line leer und braucht 1352 // nicht mit Blanks aufgefuellt werden. 1353 if( pUndo ) 1354 for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i ) 1355 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1356 1357 sal_uInt16 nCnt = nSEndPos - nSttPos; 1358 aPosArr.Remove( nSttPos, nCnt ); 1359 nESttPos -= nCnt; 1360 n -= nCnt; 1361 } 1362 if( nESttPos < n ) 1363 { 1364 // dann ist der vorder Teil der Line leer und braucht 1365 // nicht mit Blanks aufgefuellt werden. 1366 if( pUndo ) 1367 for( sal_uInt16 i = nESttPos; i < n; ++i ) 1368 pUndo->SaveCollection( *aPosArr[ i ].pSelBox ); 1369 1370 sal_uInt16 nCnt = n - nESttPos; 1371 aPosArr.Remove( nESttPos, nCnt ); 1372 } 1373 #else 1374 // DEL_ALL_EMPTY_BOXES 1375 1376 nWidth = 0; 1377 long nY = aPosArr.Count() ? 1378 ( bVert ? 1379 aPosArr[ 0 ].X() : 1380 aPosArr[ 0 ].Y() ) : 1381 0; 1382 1383 for( sal_uInt16 n = 0; n < aPosArr.Count(); ++n ) 1384 { 1385 const _CmpLPt& rPt = aPosArr[ n ]; 1386 if( bCalcWidth ) 1387 { 1388 if( nY == ( bVert ? rPt.X() : rPt.Y() ) ) // gleiche Ebene ? 1389 nWidth += rPt.pSelBox->GetFrmFmt()->GetFrmSize().GetWidth(); 1390 else 1391 bCalcWidth = sal_False; // eine Zeile fertig 1392 } 1393 1394 if( IsEmptyBox( *rPt.pSelBox, aPam ) ) 1395 { 1396 if( pUndo ) 1397 pUndo->SaveCollection( *rPt.pSelBox ); 1398 1399 aPosArr.Remove( n, 1 ); 1400 --n; 1401 } 1402 } 1403 #endif 1404 } 1405 1406 // lege schon mal die neue Box an 1407 { 1408 SwTableBox* pTmpBox = rBoxes[0]; 1409 SwTableLine* pInsLine = pTmpBox->GetUpper(); 1410 sal_uInt16 nInsPos = pInsLine->GetTabBoxes().C40_GETPOS( SwTableBox, pTmpBox ); 1411 1412 lcl_InsTblBox( pTblNd, pDoc, pTmpBox, nInsPos ); 1413 (*ppMergeBox) = pInsLine->GetTabBoxes()[ nInsPos ]; 1414 pInsLine->GetTabBoxes().Remove( nInsPos ); // wieder austragen 1415 (*ppMergeBox)->SetUpper( 0 ); 1416 (*ppMergeBox)->ClaimFrmFmt(); 1417 1418 // setze die Umrandung: von der 1. Box die linke/obere von der 1419 // letzten Box die rechte/untere Kante: 1420 if( pLastBox && pFirstBox ) 1421 { 1422 SvxBoxItem aBox( pFirstBox->GetFrmFmt()->GetBox() ); 1423 const SvxBoxItem& rBox = pLastBox->GetFrmFmt()->GetBox(); 1424 aBox.SetLine( rBox.GetRight(), BOX_LINE_RIGHT ); 1425 aBox.SetLine( rBox.GetBottom(), BOX_LINE_BOTTOM ); 1426 if( aBox.GetLeft() || aBox.GetTop() || 1427 aBox.GetRight() || aBox.GetBottom() ) 1428 (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( aBox ); 1429 } 1430 } 1431 1432 //Block damit SwPaM, SwPosition vom Stack geloescht werden 1433 if( aPosArr.Count() ) 1434 { 1435 SwTxtNode* pTxtNd = 0; 1436 SwPosition aInsPos( *(*ppMergeBox)->GetSttNd() ); 1437 SwNodeIndex& rInsPosNd = aInsPos.nNode; 1438 1439 SwPaM aPam( aInsPos ); 1440 1441 for( sal_uInt16 n = 0; n < aPosArr.Count(); ++n ) 1442 { 1443 const _CmpLPt& rPt = aPosArr[ n ]; 1444 aPam.GetPoint()->nNode.Assign( *rPt.pSelBox->GetSttNd()-> 1445 EndOfSectionNode(), -1 ); 1446 SwCntntNode* pCNd = aPam.GetCntntNode(); 1447 sal_uInt16 nL = pCNd ? pCNd->Len() : 0; 1448 aPam.GetPoint()->nContent.Assign( pCNd, nL ); 1449 1450 SwNodeIndex aSttNdIdx( *rPt.pSelBox->GetSttNd(), 1 ); 1451 // ein Node muss in der Box erhalten bleiben (sonst wird beim 1452 // Move die gesamte Section geloescht) 1453 bool const bUndo(pDoc->GetIDocumentUndoRedo().DoesUndo()); 1454 if( pUndo ) 1455 { 1456 pDoc->GetIDocumentUndoRedo().DoUndo(false); 1457 } 1458 pDoc->AppendTxtNode( *aPam.GetPoint() ); 1459 if( pUndo ) 1460 { 1461 pDoc->GetIDocumentUndoRedo().DoUndo(bUndo); 1462 } 1463 SwNodeRange aRg( aSttNdIdx, aPam.GetPoint()->nNode ); 1464 rInsPosNd++; 1465 if( pUndo ) 1466 pUndo->MoveBoxCntnt( pDoc, aRg, rInsPosNd ); 1467 else 1468 { 1469 pDoc->MoveNodeRange( aRg, rInsPosNd, 1470 IDocumentContentOperations::DOC_MOVEDEFAULT ); 1471 } 1472 // wo steht jetzt aInsPos ?? 1473 1474 if( bCalcWidth ) 1475 bCalcWidth = sal_False; // eine Zeile fertig 1476 1477 // den initialen TextNode ueberspringen 1478 rInsPosNd.Assign( pDoc->GetNodes(), 1479 rInsPosNd.GetNode().EndOfSectionIndex() - 2 ); 1480 pTxtNd = rInsPosNd.GetNode().GetTxtNode(); 1481 if( pTxtNd ) 1482 aInsPos.nContent.Assign( pTxtNd, pTxtNd->GetTxt().Len() ); 1483 } 1484 1485 // in der MergeBox sollte jetzt der gesamte Text stehen 1486 // loesche jetzt noch den initialen TextNode 1487 ASSERT( (*ppMergeBox)->GetSttIdx()+2 < 1488 (*ppMergeBox)->GetSttNd()->EndOfSectionIndex(), 1489 "leere Box" ); 1490 SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 ); 1491 pDoc->GetNodes().Delete( aIdx, 1 ); 1492 } 1493 1494 // setze die Breite der Box 1495 (*ppMergeBox)->GetFrmFmt()->SetFmtAttr( SwFmtFrmSize( ATT_VAR_SIZE, nWidth, 0 )); 1496 if( pUndo ) 1497 pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() ); 1498 } 1499 1500 1501 static sal_Bool lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara ); 1502 1503 static sal_Bool lcl_CheckRow( const _FndLine*& rpFndLine, void* pPara ) 1504 { 1505 ((_FndLine*)rpFndLine)->GetBoxes().ForEach( &lcl_CheckCol, pPara ); 1506 return *(sal_Bool*)pPara; 1507 } 1508 1509 static sal_Bool lcl_CheckCol( const _FndBox*& rpFndBox, void* pPara ) 1510 { 1511 if( !rpFndBox->GetBox()->GetSttNd() ) 1512 { 1513 if( rpFndBox->GetLines().Count() != 1514 rpFndBox->GetBox()->GetTabLines().Count() ) 1515 *((sal_Bool*)pPara) = sal_False; 1516 else 1517 ((_FndBox*)rpFndBox)->GetLines().ForEach( &lcl_CheckRow, pPara ); 1518 } 1519 // Box geschuetzt ?? 1520 else if( rpFndBox->GetBox()->GetFrmFmt()->GetProtect().IsCntntProtected() ) 1521 *((sal_Bool*)pPara) = sal_False; 1522 return *(sal_Bool*)pPara; 1523 } 1524 1525 1526 sal_uInt16 CheckMergeSel( const SwPaM& rPam ) 1527 { 1528 SwSelBoxes aBoxes; 1529 //JP 24.09.96: Merge mit wiederholenden TabellenHeadline funktioniert nicht 1530 // richtig. Warum nicht Point 0,0 benutzen? Dann ist garantiert, 1531 // das die 1. Headline mit drin ist. 1532 Point aPt; 1533 const SwCntntNode* pCntNd = rPam.GetCntntNode(); 1534 const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 1535 &aPt )->GetUpper(); 1536 pCntNd = rPam.GetCntntNode(sal_False); 1537 const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 1538 &aPt )->GetUpper(); 1539 GetTblSel( pStart, pEnd, aBoxes, 0 ); 1540 return CheckMergeSel( aBoxes ); 1541 } 1542 1543 sal_uInt16 CheckMergeSel( const SwSelBoxes& rBoxes ) 1544 { 1545 sal_uInt16 eRet = TBLMERGE_NOSELECTION; 1546 if( rBoxes.Count() ) 1547 { 1548 eRet = TBLMERGE_OK; 1549 1550 _FndBox aFndBox( 0, 0 ); 1551 _FndPara aPara( rBoxes, &aFndBox ); 1552 const SwTableNode* pTblNd = aPara.rBoxes[0]->GetSttNd()->FindTableNode(); 1553 ((SwTable&)pTblNd->GetTable()).GetTabLines().ForEach( 1554 &_FndLineCopyCol, &aPara ); 1555 if( aFndBox.GetLines().Count() ) 1556 { 1557 sal_Bool bMergeSelOk = sal_True; 1558 _FndBox* pFndBox = &aFndBox; 1559 _FndLine* pFndLine = 0; 1560 while( pFndBox && 1 == pFndBox->GetLines().Count() ) 1561 { 1562 pFndLine = pFndBox->GetLines()[0]; 1563 if( 1 == pFndLine->GetBoxes().Count() ) 1564 pFndBox = pFndLine->GetBoxes()[0]; 1565 else 1566 pFndBox = 0; 1567 } 1568 if( pFndBox ) 1569 pFndBox->GetLines().ForEach( &lcl_CheckRow, &bMergeSelOk ); 1570 else if( pFndLine ) 1571 pFndLine->GetBoxes().ForEach( &lcl_CheckCol, &bMergeSelOk ); 1572 if( !bMergeSelOk ) 1573 eRet = TBLMERGE_TOOCOMPLEX; 1574 } 1575 else 1576 eRet = TBLMERGE_NOSELECTION; 1577 } 1578 return eRet; 1579 } 1580 1581 //Ermittelt die von einer Tabellenselektion betroffenen Tabellen und die 1582 //Union-Rechteckte der Selektionen - auch fuer aufgespaltene Tabellen. 1583 SV_IMPL_PTRARR( SwSelUnions, SwSelUnion* ); 1584 1585 SwTwips lcl_CalcWish( const SwLayoutFrm *pCell, long nWish, 1586 const long nAct ) 1587 { 1588 const SwLayoutFrm *pTmp = pCell; 1589 if ( !nWish ) 1590 nWish = 1; 1591 1592 const sal_Bool bRTL = pCell->IsRightToLeft(); 1593 SwTwips nRet = bRTL ? 1594 nAct - pCell->Frm().Width() : 1595 0; 1596 1597 while ( pTmp ) 1598 { 1599 while ( pTmp->GetPrev() ) 1600 { 1601 pTmp = (SwLayoutFrm*)pTmp->GetPrev(); 1602 long nTmp = pTmp->GetFmt()->GetFrmSize().GetWidth(); 1603 nRet += ( bRTL ? ( -1 ) : 1 ) * nTmp * nAct / nWish; 1604 } 1605 pTmp = pTmp->GetUpper()->GetUpper(); 1606 if ( pTmp && !pTmp->IsCellFrm() ) 1607 pTmp = 0; 1608 } 1609 return nRet; 1610 } 1611 1612 void lcl_FindStartEndRow( const SwLayoutFrm *&rpStart, 1613 const SwLayoutFrm *&rpEnd, 1614 const int bChkProtected ) 1615 { 1616 //Start an den Anfang seiner Zeile setzen. 1617 //End an das Ende seiner Zeile setzen. 1618 rpStart = (SwLayoutFrm*)rpStart->GetUpper()->Lower(); 1619 while ( rpEnd->GetNext() ) 1620 rpEnd = (SwLayoutFrm*)rpEnd->GetNext(); 1621 1622 SvPtrarr aSttArr( 8, 8 ), aEndArr( 8, 8 ); 1623 const SwLayoutFrm *pTmp; 1624 for( pTmp = rpStart; (FRM_CELL|FRM_ROW) & pTmp->GetType(); 1625 pTmp = pTmp->GetUpper() ) 1626 { 1627 void* p = (void*)pTmp; 1628 aSttArr.Insert( p, 0 ); 1629 } 1630 for( pTmp = rpEnd; (FRM_CELL|FRM_ROW) & pTmp->GetType(); 1631 pTmp = pTmp->GetUpper() ) 1632 { 1633 void* p = (void*)pTmp; 1634 aEndArr.Insert( p, 0 ); 1635 } 1636 1637 for( sal_uInt16 n = 0; n < aEndArr.Count() && n < aSttArr.Count(); ++n ) 1638 if( aSttArr[ n ] != aEndArr[ n ] ) 1639 { 1640 // first unequal line or box - all odds are 1641 if( n & 1 ) // 1, 3, 5, ... are boxes 1642 { 1643 rpStart = (SwLayoutFrm*)aSttArr[ n ]; 1644 rpEnd = (SwLayoutFrm*)aEndArr[ n ]; 1645 } 1646 else // 0, 2, 4, ... are lines 1647 { 1648 // check if start & end line are the first & last Line of the 1649 // box. If not return these cells. 1650 // Else the hole line with all Boxes has to be deleted. 1651 rpStart = (SwLayoutFrm*)aSttArr[ n+1 ]; 1652 rpEnd = (SwLayoutFrm*)aEndArr[ n+1 ]; 1653 if( n ) 1654 { 1655 const SwCellFrm* pCellFrm = (SwCellFrm*)aSttArr[ n-1 ]; 1656 const SwTableLines& rLns = pCellFrm-> 1657 GetTabBox()->GetTabLines(); 1658 if( rLns[ 0 ] == ((SwRowFrm*)aSttArr[ n ])->GetTabLine() && 1659 rLns[ rLns.Count() - 1 ] == 1660 ((SwRowFrm*)aEndArr[ n ])->GetTabLine() ) 1661 { 1662 rpStart = rpEnd = pCellFrm; 1663 while ( rpStart->GetPrev() ) 1664 rpStart = (SwLayoutFrm*)rpStart->GetPrev(); 1665 while ( rpEnd->GetNext() ) 1666 rpEnd = (SwLayoutFrm*)rpEnd->GetNext(); 1667 } 1668 } 1669 } 1670 break; 1671 } 1672 1673 if( !bChkProtected ) // geschuetzte Zellen beachten ? 1674 return; 1675 1676 1677 //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen. 1678 while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() ) 1679 rpStart = (SwLayoutFrm*)rpStart->GetNext(); 1680 while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() ) 1681 rpEnd = (SwLayoutFrm*)rpEnd->GetPrev(); 1682 } 1683 1684 1685 void lcl_FindStartEndCol( const SwLayoutFrm *&rpStart, 1686 const SwLayoutFrm *&rpEnd, 1687 const int bChkProtected ) 1688 { 1689 //Start und End senkrecht bis an den Rand der Tabelle denken; es muss 1690 //die Gesamttabelle betrachtet werden, also inklusive Masters und 1691 //Follows. 1692 //Fuer den Start brauchen wir den Mutter-TabellenFrm. 1693 if( !rpStart ) 1694 return; 1695 const SwTabFrm *pOrg = rpStart->FindTabFrm(); 1696 const SwTabFrm *pTab = pOrg; 1697 1698 SWRECTFN( pTab ) 1699 1700 sal_Bool bRTL = pTab->IsRightToLeft(); 1701 const long nTmpWish = pOrg->GetFmt()->GetFrmSize().GetWidth(); 1702 const long nWish = ( nTmpWish > 0 ) ? nTmpWish : 1; 1703 1704 while ( pTab->IsFollow() ) 1705 { 1706 const SwFrm *pTmp = pTab->FindPrev(); 1707 ASSERT( pTmp->IsTabFrm(), "Vorgaenger vom Follow nicht der Master." ); 1708 pTab = (const SwTabFrm*)pTmp; 1709 } 1710 1711 SwTwips nSX = 0; 1712 SwTwips nSX2 = 0; 1713 1714 if ( pTab->GetTable()->IsNewModel() ) 1715 { 1716 nSX = (rpStart->Frm().*fnRect->fnGetLeft )(); 1717 nSX2 = (rpStart->Frm().*fnRect->fnGetRight)(); 1718 } 1719 else 1720 { 1721 const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)(); 1722 nSX = ::lcl_CalcWish( rpStart, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)(); 1723 nSX2 = nSX + (rpStart->GetFmt()->GetFrmSize().GetWidth() * nPrtWidth / nWish); 1724 } 1725 1726 const SwLayoutFrm *pTmp = pTab->FirstCell(); 1727 1728 while ( pTmp && 1729 (!pTmp->IsCellFrm() || 1730 ( ( ! bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() < nSX && 1731 (pTmp->Frm().*fnRect->fnGetRight)()< nSX2 ) || 1732 ( bRTL && (pTmp->Frm().*fnRect->fnGetLeft)() > nSX && 1733 (pTmp->Frm().*fnRect->fnGetRight)()> nSX2 ) ) ) ) 1734 pTmp = pTmp->GetNextLayoutLeaf(); 1735 1736 if ( pTmp ) 1737 rpStart = pTmp; 1738 1739 pTab = pOrg; 1740 1741 const SwTabFrm* pLastValidTab = pTab; 1742 while ( pTab->GetFollow() ) 1743 { 1744 // 1745 // Check if pTab->GetFollow() is a valid follow table: 1746 // Only follow tables with at least on non-FollowFlowLine 1747 // should be considered. 1748 // 1749 if ( pTab->HasFollowFlowLine() ) 1750 { 1751 pTab = pTab->GetFollow(); 1752 const SwFrm* pTmpRow = pTab->GetFirstNonHeadlineRow(); 1753 if ( pTmpRow && pTmpRow->GetNext() ) 1754 pLastValidTab = pTab; 1755 } 1756 else 1757 pLastValidTab = pTab = pTab->GetFollow(); 1758 } 1759 pTab = pLastValidTab; 1760 1761 SwTwips nEX = 0; 1762 1763 if ( pTab->GetTable()->IsNewModel() ) 1764 { 1765 nEX = (rpEnd->Frm().*fnRect->fnGetLeft )(); 1766 } 1767 else 1768 { 1769 const SwTwips nPrtWidth = (pTab->Prt().*fnRect->fnGetWidth)(); 1770 nEX = ::lcl_CalcWish( rpEnd, nWish, nPrtWidth ) + (pTab->*fnRect->fnGetPrtLeft)(); 1771 } 1772 1773 const SwCntntFrm* pLastCntnt = pTab->FindLastCntnt(); 1774 rpEnd = pLastCntnt ? pLastCntnt->GetUpper() : 0; 1775 // --> FME 2006-07-17 #134385# Made code robust. If pTab does not have a lower, 1776 // we would crash here. 1777 if ( !pLastCntnt ) return; 1778 // <-- 1779 1780 while( !rpEnd->IsCellFrm() ) 1781 rpEnd = rpEnd->GetUpper(); 1782 1783 while ( ( bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() < nEX ) || 1784 ( ! bRTL && (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) ) 1785 { 1786 const SwLayoutFrm* pTmpLeaf = rpEnd->GetPrevLayoutLeaf(); 1787 if( !pTmpLeaf || !pTab->IsAnLower( pTmpLeaf ) ) 1788 break; 1789 rpEnd = pTmpLeaf; 1790 } 1791 1792 if( !bChkProtected ) // geschuetzte Zellen beachten ? 1793 return; 1794 1795 //Anfang und Ende duerfen nicht auf geschuetzten Zellen liegen. 1796 //Also muss ggf. nocheinmal rueckwaerts gesucht werden. 1797 while ( rpStart->GetFmt()->GetProtect().IsCntntProtected() ) 1798 { 1799 const SwLayoutFrm *pTmpLeaf = rpStart; 1800 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf(); 1801 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX )//erstmal die Zeile ueberspr. 1802 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf(); 1803 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nSX && 1804 (pTmpLeaf->Frm().*fnRect->fnGetRight)()< nSX2 ) 1805 pTmpLeaf = pTmpLeaf->GetNextLayoutLeaf(); 1806 const SwTabFrm *pTmpTab = rpStart->FindTabFrm(); 1807 if ( !pTmpTab->IsAnLower( pTmpLeaf ) ) 1808 { 1809 pTmpTab = pTmpTab->GetFollow(); 1810 rpStart = pTmpTab->FirstCell(); 1811 while ( (rpStart->Frm().*fnRect->fnGetLeft)() < nSX && 1812 (rpStart->Frm().*fnRect->fnGetRight)()< nSX2 ) 1813 rpStart = rpStart->GetNextLayoutLeaf(); 1814 } 1815 else 1816 rpStart = pTmpLeaf; 1817 } 1818 while ( rpEnd->GetFmt()->GetProtect().IsCntntProtected() ) 1819 { 1820 const SwLayoutFrm *pTmpLeaf = rpEnd; 1821 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf(); 1822 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() < nEX )//erstmal die Zeile ueberspr. 1823 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf(); 1824 while ( pTmpLeaf && (pTmpLeaf->Frm().*fnRect->fnGetLeft)() > nEX ) 1825 pTmpLeaf = pTmpLeaf->GetPrevLayoutLeaf(); 1826 const SwTabFrm *pTmpTab = rpEnd->FindTabFrm(); 1827 if ( !pTmpLeaf || !pTmpTab->IsAnLower( pTmpLeaf ) ) 1828 { 1829 pTmpTab = (const SwTabFrm*)pTmpTab->FindPrev(); 1830 ASSERT( pTmpTab->IsTabFrm(), "Vorgaenger vom Follow nicht der Master."); 1831 rpEnd = pTmpTab->FindLastCntnt()->GetUpper(); 1832 while( !rpEnd->IsCellFrm() ) 1833 rpEnd = rpEnd->GetUpper(); 1834 while ( (rpEnd->Frm().*fnRect->fnGetLeft)() > nEX ) 1835 rpEnd = rpEnd->GetPrevLayoutLeaf(); 1836 } 1837 else 1838 rpEnd = pTmpLeaf; 1839 } 1840 } 1841 1842 1843 void MakeSelUnions( SwSelUnions& rUnions, const SwLayoutFrm *pStart, 1844 const SwLayoutFrm *pEnd, const SwTblSearchType eSearchType ) 1845 { 1846 while ( pStart && !pStart->IsCellFrm() ) 1847 pStart = pStart->GetUpper(); 1848 while ( pEnd && !pEnd->IsCellFrm() ) 1849 pEnd = pEnd->GetUpper(); 1850 1851 // #112697# Robust: 1852 if ( !pStart || !pEnd ) 1853 { 1854 ASSERT( false, "MakeSelUnions with pStart or pEnd not in CellFrm" ) 1855 return; 1856 } 1857 1858 const SwTabFrm *pTable = pStart->FindTabFrm(); 1859 const SwTabFrm *pEndTable = pEnd->FindTabFrm(); 1860 if( !pTable || !pEndTable ) 1861 return; 1862 sal_Bool bExchange = sal_False; 1863 1864 if ( pTable != pEndTable ) 1865 { 1866 if ( !pTable->IsAnFollow( pEndTable ) ) 1867 { 1868 ASSERT( pEndTable->IsAnFollow( pTable ), "Tabkette verknotet." ); 1869 bExchange = sal_True; 1870 } 1871 } 1872 else 1873 { 1874 SWRECTFN( pTable ) 1875 long nSttTop = (pStart->Frm().*fnRect->fnGetTop)(); 1876 long nEndTop = (pEnd->Frm().*fnRect->fnGetTop)(); 1877 if( nSttTop == nEndTop ) 1878 { 1879 if( (pStart->Frm().*fnRect->fnGetLeft)() > 1880 (pEnd->Frm().*fnRect->fnGetLeft)() ) 1881 bExchange = sal_True; 1882 } 1883 else if( bVert == ( nSttTop < nEndTop ) ) 1884 bExchange = sal_True; 1885 } 1886 if ( bExchange ) 1887 { 1888 const SwLayoutFrm *pTmp = pStart; 1889 pStart = pEnd; 1890 pEnd = pTmp; 1891 //pTable und pEndTable nicht umsortieren, werden unten neu gesetzt. 1892 //MA: 28. Dec. 93 Bug: 5190 1893 } 1894 1895 //Start und End sind jetzt huebsch sortiert, jetzt muessen sie falls 1896 //erwuenscht noch versetzt werden. 1897 if( nsSwTblSearchType::TBLSEARCH_ROW == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) ) 1898 ::lcl_FindStartEndRow( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType ); 1899 else if( nsSwTblSearchType::TBLSEARCH_COL == ((~nsSwTblSearchType::TBLSEARCH_PROTECT ) & eSearchType ) ) 1900 ::lcl_FindStartEndCol( pStart, pEnd, nsSwTblSearchType::TBLSEARCH_PROTECT & eSearchType ); 1901 1902 // --> FME 2006-07-17 #134385# Made code robust. 1903 if ( !pEnd ) return; 1904 // <-- 1905 1906 //neu besorgen, da sie jetzt verschoben sind. MA: 28. Dec. 93 Bug 5190 1907 pTable = pStart->FindTabFrm(); 1908 pEndTable = pEnd->FindTabFrm(); 1909 1910 const long nStSz = pStart->GetFmt()->GetFrmSize().GetWidth(); 1911 const long nEdSz = pEnd->GetFmt()->GetFrmSize().GetWidth(); 1912 const long nWish = Max( 1L, pTable->GetFmt()->GetFrmSize().GetWidth() ); 1913 while ( pTable ) 1914 { 1915 SWRECTFN( pTable ) 1916 const long nOfst = (pTable->*fnRect->fnGetPrtLeft)(); 1917 const long nPrtWidth = (pTable->Prt().*fnRect->fnGetWidth)(); 1918 long nSt1 = ::lcl_CalcWish( pStart, nWish, nPrtWidth ) + nOfst; 1919 long nEd1 = ::lcl_CalcWish( pEnd, nWish, nPrtWidth ) + nOfst; 1920 1921 if ( nSt1 <= nEd1 ) 1922 nEd1 += (long)((nEdSz * nPrtWidth) / nWish) - 1; 1923 else 1924 nSt1 += (long)((nStSz * nPrtWidth) / nWish) - 1; 1925 1926 long nSt2; 1927 long nEd2; 1928 if( pTable->IsAnLower( pStart ) ) 1929 nSt2 = (pStart->Frm().*fnRect->fnGetTop)(); 1930 else 1931 nSt2 = (pTable->Frm().*fnRect->fnGetTop)(); 1932 if( pTable->IsAnLower( pEnd ) ) 1933 nEd2 = (pEnd->Frm().*fnRect->fnGetBottom)(); 1934 else 1935 nEd2 = (pTable->Frm().*fnRect->fnGetBottom)(); 1936 Point aSt, aEd; 1937 if( nSt1 > nEd1 ) 1938 { 1939 long nTmp = nSt1; 1940 nSt1 = nEd1; 1941 nEd1 = nTmp; 1942 } 1943 if( nSt2 > nEd2 ) 1944 { 1945 long nTmp = nSt2; 1946 nSt2 = nEd2; 1947 nEd2 = nTmp; 1948 } 1949 if( bVert ) 1950 { 1951 aSt = Point( nSt2, nSt1 ); 1952 aEd = Point( nEd2, nEd1 ); 1953 } 1954 else 1955 { 1956 aSt = Point( nSt1, nSt2 ); 1957 aEd = Point( nEd1, nEd2 ); 1958 } 1959 1960 const Point aDiff( aEd - aSt ); 1961 SwRect aUnion( aSt, Size( aDiff.X(), aDiff.Y() ) ); 1962 aUnion.Justify(); 1963 1964 // fuers 1965 if( !(nsSwTblSearchType::TBLSEARCH_NO_UNION_CORRECT & eSearchType )) 1966 { 1967 //Leider ist die Union jetzt mit Rundungsfehlern behaftet und dadurch 1968 //wuerden beim Split/Merge fehlertraechtige Umstaende entstehen. 1969 //Um dies zu vermeiden werden jetzt fuer die Table die erste und 1970 //letzte Zelle innerhalb der Union ermittelt und aus genau deren 1971 //Werten wird die Union neu gebildet. 1972 const SwLayoutFrm* pRow = pTable->IsFollow() ? 1973 pTable->GetFirstNonHeadlineRow() : 1974 (const SwLayoutFrm*)pTable->Lower(); 1975 1976 while ( pRow && !pRow->Frm().IsOver( aUnion ) ) 1977 pRow = (SwLayoutFrm*)pRow->GetNext(); 1978 1979 // --> FME 2004-07-26 #i31976# 1980 // A follow flow row may contain emtpy cells. These are not 1981 // considered by FirstCell(). Therefore we have to find 1982 // the first cell manually: 1983 const SwFrm* pTmpCell = 0; 1984 if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() ) 1985 { 1986 const SwFrm* pTmpRow = pRow; 1987 while ( pTmpRow && pTmpRow->IsRowFrm() ) 1988 { 1989 pTmpCell = static_cast<const SwRowFrm*>(pTmpRow)->Lower(); 1990 pTmpRow = static_cast<const SwCellFrm*>(pTmpCell)->Lower(); 1991 } 1992 ASSERT( !pTmpCell || pTmpCell->IsCellFrm(), "Lower of rowframe != cellframe?!" ) 1993 } 1994 // <-- 1995 1996 const SwLayoutFrm* pFirst = pTmpCell ? 1997 static_cast<const SwLayoutFrm*>(pTmpCell) : 1998 pRow ? 1999 pRow->FirstCell() : 2000 0; 2001 2002 while ( pFirst && !::IsFrmInTblSel( aUnion, pFirst ) ) 2003 { 2004 if ( pFirst->GetNext() ) 2005 { 2006 pFirst = (const SwLayoutFrm*)pFirst->GetNext(); 2007 if ( pFirst->Lower() && pFirst->Lower()->IsRowFrm() ) 2008 pFirst = pFirst->FirstCell(); 2009 } 2010 else 2011 pFirst = ::lcl_FindNextCellFrm( pFirst ); 2012 } 2013 const SwLayoutFrm* pLast = 0; 2014 const SwFrm* pLastCntnt = pTable->FindLastCntnt(); 2015 if ( pLastCntnt ) 2016 pLast = ::lcl_FindCellFrm( pLastCntnt->GetUpper() ); 2017 2018 while ( pLast && !::IsFrmInTblSel( aUnion, pLast ) ) 2019 pLast = ::lcl_FindCellFrm( pLast->GetPrevLayoutLeaf() ); 2020 2021 if ( pFirst && pLast ) //Robust 2022 { 2023 aUnion = pFirst->Frm(); 2024 aUnion.Union( pLast->Frm() ); 2025 } 2026 else 2027 aUnion.Width( 0 ); 2028 } 2029 2030 if( (aUnion.*fnRect->fnGetWidth)() ) 2031 { 2032 SwSelUnion *pTmp = new SwSelUnion( aUnion, (SwTabFrm*)pTable ); 2033 rUnions.C40_INSERT( SwSelUnion, pTmp, rUnions.Count() ); 2034 } 2035 2036 pTable = pTable->GetFollow(); 2037 if ( pTable != pEndTable && pEndTable->IsAnFollow( pTable ) ) 2038 pTable = 0; 2039 } 2040 } 2041 2042 sal_Bool CheckSplitCells( const SwCrsrShell& rShell, sal_uInt16 nDiv, 2043 const SwTblSearchType eSearchType ) 2044 { 2045 if( !rShell.IsTableMode() ) 2046 rShell.GetCrsr(); 2047 2048 return CheckSplitCells( *rShell.getShellCrsr(false), nDiv, eSearchType ); 2049 } 2050 2051 sal_Bool CheckSplitCells( const SwCursor& rCrsr, sal_uInt16 nDiv, 2052 const SwTblSearchType eSearchType ) 2053 { 2054 if( 1 >= nDiv ) 2055 return sal_False; 2056 2057 sal_uInt16 nMinValue = nDiv * MINLAY; 2058 2059 //Start- und Endzelle besorgen und den naechsten fragen. 2060 Point aPtPos, aMkPos; 2061 const SwShellCrsr* pShCrsr = dynamic_cast<const SwShellCrsr*>(&rCrsr); 2062 if( pShCrsr ) 2063 { 2064 aPtPos = pShCrsr->GetPtPos(); 2065 aMkPos = pShCrsr->GetMkPos(); 2066 } 2067 2068 const SwCntntNode* pCntNd = rCrsr.GetCntntNode(); 2069 const SwLayoutFrm *pStart = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 2070 &aPtPos )->GetUpper(); 2071 pCntNd = rCrsr.GetCntntNode(sal_False); 2072 const SwLayoutFrm *pEnd = pCntNd->getLayoutFrm( pCntNd->GetDoc()->GetCurrentLayout(), 2073 &aMkPos )->GetUpper(); 2074 2075 SWRECTFN( pStart->GetUpper() ) 2076 2077 //Zuerst lassen wir uns die Tabellen und die Rechtecke heraussuchen. 2078 SwSelUnions aUnions; 2079 2080 ::MakeSelUnions( aUnions, pStart, pEnd, eSearchType ); 2081 2082 //Jetzt zu jedem Eintrag die Boxen herausfischen und uebertragen. 2083 for ( sal_uInt16 i = 0; i < aUnions.Count(); ++i ) 2084 { 2085 SwSelUnion *pUnion = aUnions[i]; 2086 const SwTabFrm *pTable = pUnion->GetTable(); 2087 2088 // Skip any repeated headlines in the follow: 2089 const SwLayoutFrm* pRow = pTable->IsFollow() ? 2090 pTable->GetFirstNonHeadlineRow() : 2091 (const SwLayoutFrm*)pTable->Lower(); 2092 2093 while ( pRow ) 2094 { 2095 if ( pRow->Frm().IsOver( pUnion->GetUnion() ) ) 2096 { 2097 const SwLayoutFrm *pCell = pRow->FirstCell(); 2098 2099 while ( pCell && pRow->IsAnLower( pCell ) ) 2100 { 2101 ASSERT( pCell->IsCellFrm(), "Frame ohne Celle" ); 2102 if( ::IsFrmInTblSel( pUnion->GetUnion(), pCell ) ) 2103 { 2104 if( (pCell->Frm().*fnRect->fnGetWidth)() < nMinValue ) 2105 return sal_False; 2106 } 2107 2108 if ( pCell->GetNext() ) 2109 { 2110 pCell = (const SwLayoutFrm*)pCell->GetNext(); 2111 if ( pCell->Lower() && pCell->Lower()->IsRowFrm() ) 2112 pCell = pCell->FirstCell(); 2113 } 2114 else 2115 pCell = ::lcl_FindNextCellFrm( pCell ); 2116 } 2117 } 2118 pRow = (const SwLayoutFrm*)pRow->GetNext(); 2119 } 2120 } 2121 return sal_True; 2122 } 2123 2124 // ------------------------------------------------------------------- 2125 // Diese Klassen kopieren die aktuelle Tabellen-Selektion (rBoxes) 2126 // unter Beibehaltung der Tabellen-Struktur in eine eigene Struktur 2127 // neu: SS zum gezielten Loeschen/Retaurieren des Layouts. 2128 2129 void lcl_InsertRow( SwTableLine &rLine, SwLayoutFrm *pUpper, SwFrm *pSibling ) 2130 { 2131 SwRowFrm *pRow = new SwRowFrm( rLine, pUpper ); 2132 if ( pUpper->IsTabFrm() && ((SwTabFrm*)pUpper)->IsFollow() ) 2133 { 2134 SwTabFrm* pTabFrm = (SwTabFrm*)pUpper; 2135 pTabFrm->FindMaster()->InvalidatePos(); //kann die Zeile vielleicht aufnehmen 2136 2137 if ( pSibling && pTabFrm->IsInHeadline( *pSibling ) ) 2138 { 2139 // Skip any repeated headlines in the follow: 2140 pSibling = pTabFrm->GetFirstNonHeadlineRow(); 2141 } 2142 } 2143 pRow->Paste( pUpper, pSibling ); 2144 pRow->RegistFlys(); 2145 } 2146 2147 2148 sal_Bool _FndBoxCopyCol( const SwTableBox*& rpBox, void* pPara ) 2149 { 2150 _FndPara* pFndPara = (_FndPara*)pPara; 2151 _FndBox* pFndBox = new _FndBox( (SwTableBox*)rpBox, pFndPara->pFndLine ); 2152 if( rpBox->GetTabLines().Count() ) 2153 { 2154 _FndPara aPara( *pFndPara, pFndBox ); 2155 pFndBox->GetBox()->GetTabLines().ForEach( &_FndLineCopyCol, &aPara ); 2156 if( !pFndBox->GetLines().Count() ) 2157 { 2158 delete pFndBox; 2159 return sal_True; 2160 } 2161 } 2162 else 2163 { 2164 SwTableBoxPtr pSrch = (SwTableBoxPtr)rpBox; 2165 sal_uInt16 nFndPos; 2166 if( !pFndPara->rBoxes.Seek_Entry( pSrch, &nFndPos )) 2167 { 2168 delete pFndBox; 2169 return sal_True; 2170 } 2171 } 2172 pFndPara->pFndLine->GetBoxes().C40_INSERT( _FndBox, pFndBox, 2173 pFndPara->pFndLine->GetBoxes().Count() ); 2174 return sal_True; 2175 } 2176 2177 sal_Bool _FndLineCopyCol( const SwTableLine*& rpLine, void* pPara ) 2178 { 2179 _FndPara* pFndPara = (_FndPara*)pPara; 2180 _FndLine* pFndLine = new _FndLine( (SwTableLine*)rpLine, pFndPara->pFndBox ); 2181 _FndPara aPara( *pFndPara, pFndLine ); 2182 pFndLine->GetLine()->GetTabBoxes().ForEach( &_FndBoxCopyCol, &aPara ); 2183 if( pFndLine->GetBoxes().Count() ) 2184 { 2185 pFndPara->pFndBox->GetLines().C40_INSERT( _FndLine, pFndLine, 2186 pFndPara->pFndBox->GetLines().Count() ); 2187 } 2188 else 2189 delete pFndLine; 2190 return sal_True; 2191 } 2192 2193 void _FndBox::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable ) 2194 { 2195 //Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich 2196 //setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen 2197 //sind, so bleiben die Pointer eben einfach 0. 2198 //Gesucht werden zunachst die Positionen der ersten/letzten betroffenen 2199 //Line im Array der SwTable. Damit die 0 fuer 'keine Line' verwand werden 2200 //kann werden die Positionen um 1 nach oben versetzt! 2201 2202 sal_uInt16 nStPos = USHRT_MAX; 2203 sal_uInt16 nEndPos= 0; 2204 2205 for ( sal_uInt16 i = 0; i < rBoxes.Count(); ++i ) 2206 { 2207 SwTableLine *pLine = rBoxes[i]->GetUpper(); 2208 while ( pLine->GetUpper() ) 2209 pLine = pLine->GetUpper()->GetUpper(); 2210 const sal_uInt16 nPos = rTable.GetTabLines().GetPos( 2211 (const SwTableLine*&)pLine ) + 1; 2212 2213 ASSERT( nPos != USHRT_MAX, "TableLine not found." ); 2214 2215 if( nStPos > nPos ) 2216 nStPos = nPos; 2217 2218 if( nEndPos < nPos ) 2219 nEndPos = nPos; 2220 } 2221 if ( nStPos > 1 ) 2222 pLineBefore = rTable.GetTabLines()[nStPos - 2]; 2223 if ( nEndPos < rTable.GetTabLines().Count() ) 2224 pLineBehind = rTable.GetTabLines()[nEndPos]; 2225 } 2226 2227 void _FndBox::SetTableLines( const SwTable &rTable ) 2228 { 2229 // Pointer auf die Lines vor und hinter den zu verarbeitenden Bereich 2230 // setzen. Wenn die erste/letzte Zeile in den Bereich eingeschlossen 2231 // sind, so bleiben die Pointer eben einfach 0. 2232 // Die Positionen der ersten/letzten betroffenen Line im Array der 2233 // SwTable steht in der FndBox. Damit die 0 fuer 'keine Line' verwand 2234 // werdenkann werden die Positionen um 1 nach oben versetzt! 2235 2236 if( !GetLines().Count() ) 2237 return; 2238 2239 SwTableLine* pTmpLine = GetLines()[0]->GetLine(); 2240 sal_uInt16 nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine ); 2241 ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" ); 2242 if( nPos ) 2243 pLineBefore = rTable.GetTabLines()[ nPos - 1 ]; 2244 2245 pTmpLine = GetLines()[GetLines().Count()-1]->GetLine(); 2246 nPos = rTable.GetTabLines().C40_GETPOS( SwTableLine, pTmpLine ); 2247 ASSERT( USHRT_MAX != nPos, "Line steht nicht in der Tabelle" ); 2248 if( ++nPos < rTable.GetTabLines().Count() ) 2249 pLineBehind = rTable.GetTabLines()[nPos]; 2250 } 2251 2252 inline void UnsetFollow( SwFlowFrm *pTab ) 2253 { 2254 pTab->bIsFollow = sal_False; 2255 } 2256 2257 void _FndBox::DelFrms( SwTable &rTable ) 2258 { 2259 //Alle Lines zwischen pLineBefore und pLineBehind muessen aus dem 2260 //Layout ausgeschnitten und geloescht werden. 2261 //Entstehen dabei leere Follows so muessen diese vernichtet werden. 2262 //Wird ein Master vernichtet, so muss der Follow Master werden. 2263 //Ein TabFrm muss immer uebrigbleiben. 2264 2265 sal_uInt16 nStPos = 0; 2266 sal_uInt16 nEndPos= rTable.GetTabLines().Count() - 1; 2267 if( rTable.IsNewModel() && pLineBefore ) 2268 rTable.CheckRowSpan( pLineBefore, true ); 2269 if ( pLineBefore ) 2270 { 2271 nStPos = rTable.GetTabLines().GetPos( 2272 (const SwTableLine*&)pLineBefore ); 2273 ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); 2274 ++nStPos; 2275 } 2276 if( rTable.IsNewModel() && pLineBehind ) 2277 rTable.CheckRowSpan( pLineBehind, false ); 2278 if ( pLineBehind ) 2279 { 2280 nEndPos = rTable.GetTabLines().GetPos( 2281 (const SwTableLine*&)pLineBehind ); 2282 ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); 2283 --nEndPos; 2284 } 2285 2286 for ( sal_uInt16 i = nStPos; i <= nEndPos; ++i) 2287 { 2288 SwFrmFmt *pFmt = rTable.GetTabLines()[i]->GetFrmFmt(); 2289 SwIterator<SwRowFrm,SwFmt> aIter( *pFmt ); 2290 for ( SwRowFrm* pFrm = aIter.First(); pFrm; pFrm = aIter.Next() ) 2291 { 2292 if ( pFrm->GetTabLine() == rTable.GetTabLines()[i] ) 2293 { 2294 sal_Bool bDel = sal_True; 2295 SwTabFrm *pUp = !pFrm->GetPrev() && !pFrm->GetNext() ? 2296 (SwTabFrm*)pFrm->GetUpper() : 0; 2297 if ( !pUp ) 2298 { 2299 const sal_uInt16 nRepeat = 2300 ((SwTabFrm*)pFrm->GetUpper())->GetTable()->GetRowsToRepeat(); 2301 if ( nRepeat > 0 && 2302 ((SwTabFrm*)pFrm->GetUpper())->IsFollow() ) 2303 { 2304 if ( !pFrm->GetNext() ) 2305 { 2306 SwRowFrm* pFirstNonHeadline = 2307 ((SwTabFrm*)pFrm->GetUpper())->GetFirstNonHeadlineRow(); 2308 if ( pFirstNonHeadline == pFrm ) 2309 { 2310 pUp = (SwTabFrm*)pFrm->GetUpper(); 2311 } 2312 } 2313 } 2314 } 2315 if ( pUp ) 2316 { 2317 SwTabFrm *pFollow = pUp->GetFollow(); 2318 SwTabFrm *pPrev = pUp->IsFollow() ? pUp : 0; 2319 if ( pPrev ) 2320 { 2321 SwFrm *pTmp = pPrev->FindPrev(); 2322 ASSERT( pTmp->IsTabFrm(), 2323 "Vorgaenger vom Follow kein Master."); 2324 pPrev = (SwTabFrm*)pTmp; 2325 } 2326 if ( pPrev ) 2327 { 2328 pPrev->SetFollow( pFollow ); 2329 // --> FME 2006-01-31 #i60340# Do not transfer the 2330 // flag from pUp to pPrev. pUp may still have the 2331 // flag set although there is not more follow flow 2332 // line associated with pUp. 2333 pPrev->SetFollowFlowLine( sal_False ); 2334 // <-- 2335 } 2336 else if ( pFollow ) 2337 ::UnsetFollow( pFollow ); 2338 2339 //Ein TabellenFrm muss immer stehenbleiben! 2340 if ( pPrev || pFollow ) 2341 { 2342 // OD 26.08.2003 #i18103# - if table is in a section, 2343 // lock the section, to avoid its delete. 2344 { 2345 SwSectionFrm* pSctFrm = pUp->FindSctFrm(); 2346 bool bOldSectLock = false; 2347 if ( pSctFrm ) 2348 { 2349 bOldSectLock = pSctFrm->IsColLocked(); 2350 pSctFrm->ColLock(); 2351 } 2352 pUp->Cut(); 2353 if ( pSctFrm && !bOldSectLock ) 2354 { 2355 pSctFrm->ColUnlock(); 2356 } 2357 } 2358 delete pUp; 2359 bDel = sal_False;//Die Row wird mit in den Abgrund 2360 //gerissen. 2361 } 2362 } 2363 if ( bDel ) 2364 { 2365 SwFrm* pTabFrm = pFrm->GetUpper(); 2366 if ( pTabFrm->IsTabFrm() && 2367 !pFrm->GetNext() && 2368 ((SwTabFrm*)pTabFrm)->GetFollow() ) 2369 { 2370 // We do not delete the follow flow line, 2371 // this will be done automatically in the 2372 // next turn. 2373 ((SwTabFrm*)pTabFrm)->SetFollowFlowLine( sal_False ); 2374 } 2375 2376 pFrm->Cut(); 2377 delete pFrm; 2378 } 2379 } 2380 } 2381 } 2382 } 2383 2384 sal_Bool lcl_IsLineOfTblFrm( const SwTabFrm& rTable, const SwFrm& rChk ) 2385 { 2386 const SwTabFrm* pTblFrm = rChk.FindTabFrm(); 2387 if( pTblFrm->IsFollow() ) 2388 pTblFrm = pTblFrm->FindMaster( true ); 2389 return &rTable == pTblFrm; 2390 } 2391 2392 /* 2393 * lcl_UpdateRepeatedHeadlines 2394 */ 2395 void lcl_UpdateRepeatedHeadlines( SwTabFrm& rTabFrm, bool bCalcLowers ) 2396 { 2397 ASSERT( rTabFrm.IsFollow(), "lcl_UpdateRepeatedHeadlines called for non-follow tab" ) 2398 2399 // Delete remaining headlines: 2400 SwRowFrm* pLower = 0; 2401 while ( 0 != ( pLower = (SwRowFrm*)rTabFrm.Lower() ) && pLower->IsRepeatedHeadline() ) 2402 { 2403 pLower->Cut(); 2404 delete pLower; 2405 } 2406 2407 // Insert fresh set of headlines: 2408 pLower = (SwRowFrm*)rTabFrm.Lower(); 2409 SwTable& rTable = *rTabFrm.GetTable(); 2410 const sal_uInt16 nRepeat = rTable.GetRowsToRepeat(); 2411 for ( sal_uInt16 nIdx = 0; nIdx < nRepeat; ++nIdx ) 2412 { 2413 SwRowFrm* pHeadline = new SwRowFrm( *rTable.GetTabLines()[ nIdx ], &rTabFrm ); 2414 pHeadline->SetRepeatedHeadline( true ); 2415 pHeadline->Paste( &rTabFrm, pLower ); 2416 pHeadline->RegistFlys(); 2417 } 2418 2419 if ( bCalcLowers ) 2420 rTabFrm.SetCalcLowers(); 2421 } 2422 2423 void _FndBox::MakeFrms( SwTable &rTable ) 2424 { 2425 //Alle Lines zwischen pLineBefore und pLineBehind muessen im Layout 2426 //wieder neu erzeugt werden. 2427 //Und Zwar fuer alle Auspraegungen der Tabelle (mehrere z.B. im Kopf/Fuss). 2428 2429 sal_uInt16 nStPos = 0; 2430 sal_uInt16 nEndPos= rTable.GetTabLines().Count() - 1; 2431 if ( pLineBefore ) 2432 { 2433 nStPos = rTable.GetTabLines().GetPos( 2434 (const SwTableLine*&)pLineBefore ); 2435 ASSERT( nStPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); 2436 ++nStPos; 2437 2438 } 2439 if ( pLineBehind ) 2440 { 2441 nEndPos = rTable.GetTabLines().GetPos( 2442 (const SwTableLine*&)pLineBehind ); 2443 ASSERT( nEndPos != USHRT_MAX, "Fuchs Du hast die Line gestohlen!" ); 2444 --nEndPos; 2445 } 2446 //Jetzt die grosse Einfuegeoperation fuer alle Tabllen. 2447 SwIterator<SwTabFrm,SwFmt> aTabIter( *rTable.GetFrmFmt() ); 2448 for ( SwTabFrm *pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() ) 2449 { 2450 if ( !pTable->IsFollow() ) 2451 { 2452 SwRowFrm *pSibling = 0; 2453 SwFrm *pUpperFrm = 0; 2454 int i; 2455 for ( i = rTable.GetTabLines().Count()-1; 2456 i >= 0 && !pSibling; --i ) 2457 { 2458 SwTableLine *pLine = pLineBehind ? pLineBehind : 2459 rTable.GetTabLines()[static_cast<sal_uInt16>(i)]; 2460 SwIterator<SwRowFrm,SwFmt> aIter( *pLine->GetFrmFmt() ); 2461 pSibling = aIter.First(); 2462 while ( pSibling && ( 2463 pSibling->GetTabLine() != pLine || 2464 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) || 2465 pSibling->IsRepeatedHeadline() || 2466 // --> FME 2005-08-24 #i53647# If !pLineBehind, 2467 // IsInSplitTableRow() should be checked. 2468 ( pLineBehind && pSibling->IsInFollowFlowRow() ) || 2469 (!pLineBehind && pSibling->IsInSplitTableRow() ) ) ) 2470 // <-- 2471 { 2472 pSibling = aIter.Next(); 2473 } 2474 } 2475 if ( pSibling ) 2476 { 2477 pUpperFrm = pSibling->GetUpper(); 2478 if ( !pLineBehind ) 2479 pSibling = 0; 2480 } 2481 else 2482 // ???? oder das der Letzte Follow der Tabelle ???? 2483 pUpperFrm = pTable; 2484 2485 for ( i = nStPos; (sal_uInt16)i <= nEndPos; ++i ) 2486 ::lcl_InsertRow( *rTable.GetTabLines()[static_cast<sal_uInt16>(i)], 2487 (SwLayoutFrm*)pUpperFrm, pSibling ); 2488 if ( pUpperFrm->IsTabFrm() ) 2489 ((SwTabFrm*)pUpperFrm)->SetCalcLowers(); 2490 } 2491 else if ( rTable.GetRowsToRepeat() > 0 ) 2492 { 2493 // Insert new headlines: 2494 lcl_UpdateRepeatedHeadlines( *pTable, true ); 2495 } 2496 } 2497 } 2498 2499 void _FndBox::MakeNewFrms( SwTable &rTable, const sal_uInt16 nNumber, 2500 const sal_Bool bBehind ) 2501 { 2502 //Frms fuer neu eingefuege Zeilen erzeugen. 2503 //bBehind == sal_True: vor pLineBehind 2504 // == sal_False: hinter pLineBefore 2505 const sal_uInt16 nBfPos = pLineBefore ? 2506 rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBefore ) : 2507 USHRT_MAX; 2508 const sal_uInt16 nBhPos = pLineBehind ? 2509 rTable.GetTabLines().GetPos( (const SwTableLine*&)pLineBehind ) : 2510 USHRT_MAX; 2511 2512 //nNumber: wie oft ist eingefuegt worden. 2513 //nCnt: wieviele sind nNumber mal eingefuegt worden. 2514 2515 const sal_uInt16 nCnt = 2516 ((nBhPos != USHRT_MAX ? nBhPos : rTable.GetTabLines().Count()) - 2517 (nBfPos != USHRT_MAX ? nBfPos + 1 : 0)) / (nNumber + 1); 2518 2519 //Den Master-TabFrm suchen 2520 SwIterator<SwTabFrm,SwFmt> aTabIter( *rTable.GetFrmFmt() ); 2521 SwTabFrm *pTable; 2522 for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() ) 2523 { 2524 if( !pTable->IsFollow() ) 2525 { 2526 SwRowFrm* pSibling = 0; 2527 SwLayoutFrm *pUpperFrm = 0; 2528 if ( bBehind ) 2529 { 2530 if ( pLineBehind ) 2531 { 2532 SwIterator<SwRowFrm,SwFmt> aIter( *pLineBehind->GetFrmFmt() ); 2533 pSibling = aIter.First(); 2534 while ( pSibling && ( 2535 // only consider row frames associated with pLineBehind: 2536 pSibling->GetTabLine() != pLineBehind || 2537 // only consider row frames that are in pTables Master-Follow chain: 2538 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) || 2539 // only consider row frames that are not repeated headlines: 2540 pSibling->IsRepeatedHeadline() || 2541 // only consider row frames that are not follow flow rows 2542 pSibling->IsInFollowFlowRow() ) ) 2543 { 2544 pSibling = aIter.Next(); 2545 } 2546 } 2547 if ( pSibling ) 2548 pUpperFrm = pSibling->GetUpper(); 2549 else 2550 { 2551 while( pTable->GetFollow() ) 2552 pTable = pTable->GetFollow(); 2553 pUpperFrm = pTable; 2554 } 2555 const sal_uInt16 nMax = nBhPos != USHRT_MAX ? 2556 nBhPos : rTable.GetTabLines().Count(); 2557 2558 sal_uInt16 i = nBfPos != USHRT_MAX ? nBfPos + 1 + nCnt : nCnt; 2559 2560 for ( ; i < nMax; ++i ) 2561 ::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrm, pSibling ); 2562 if ( pUpperFrm->IsTabFrm() ) 2563 ((SwTabFrm*)pUpperFrm)->SetCalcLowers(); 2564 } 2565 else //davor einfuegen 2566 { 2567 sal_uInt16 i; 2568 2569 // We are looking for the frame that is behind the row frame 2570 // that should be inserted. 2571 for ( i = 0; !pSibling; ++i ) 2572 { 2573 SwTableLine* pLine = pLineBefore ? pLineBefore : rTable.GetTabLines()[i]; 2574 2575 SwIterator<SwRowFrm,SwFmt> aIter( *pLine->GetFrmFmt() ); 2576 pSibling = aIter.First(); 2577 2578 while ( pSibling && ( 2579 // only consider row frames associated with pLineBefore: 2580 pSibling->GetTabLine() != pLine || 2581 // only consider row frames that are in pTables Master-Follow chain: 2582 !lcl_IsLineOfTblFrm( *pTable, *pSibling ) || 2583 // only consider row frames that are not repeated headlines: 2584 pSibling->IsRepeatedHeadline() || 2585 // 1. case: pLineBefore == 0: 2586 // only consider row frames that are not follow flow rows 2587 // 2. case: pLineBefore != 0: 2588 // only consider row frames that are not split table rows 2589 // --> FME 2004-11-23 #i37476# If !pLineBefore, 2590 // check IsInFollowFlowRow instead of IsInSplitTableRow. 2591 ( ( !pLineBefore && pSibling->IsInFollowFlowRow() ) || 2592 ( pLineBefore && pSibling->IsInSplitTableRow() ) ) ) ) 2593 // <-- 2594 { 2595 pSibling = aIter.Next(); 2596 } 2597 } 2598 2599 pUpperFrm = pSibling->GetUpper(); 2600 if ( pLineBefore ) 2601 pSibling = (SwRowFrm*) pSibling->GetNext(); 2602 2603 sal_uInt16 nMax = nBhPos != USHRT_MAX ? 2604 nBhPos - nCnt : 2605 rTable.GetTabLines().Count() - nCnt; 2606 2607 i = nBfPos != USHRT_MAX ? nBfPos + 1 : 0; 2608 for ( ; i < nMax; ++i ) 2609 ::lcl_InsertRow( *rTable.GetTabLines()[i], 2610 pUpperFrm, pSibling ); 2611 if ( pUpperFrm->IsTabFrm() ) 2612 ((SwTabFrm*)pUpperFrm)->SetCalcLowers(); 2613 } 2614 } 2615 } 2616 2617 //Die Headlines mussen ggf. auch verarbeitet werden. Um gut arbeitenden 2618 //Code nicht zu zerfasern wird hier nochmals iteriert. 2619 const sal_uInt16 nRowsToRepeat = rTable.GetRowsToRepeat(); 2620 if ( nRowsToRepeat > 0 && 2621 ( ( !bBehind && ( nBfPos == USHRT_MAX || nBfPos + 1 < nRowsToRepeat ) ) || 2622 ( bBehind && ( ( nBfPos == USHRT_MAX && nRowsToRepeat > 1 ) || nBfPos + 2 < nRowsToRepeat ) ) ) ) 2623 { 2624 for ( pTable = aTabIter.First(); pTable; pTable = aTabIter.Next() ) 2625 { 2626 if ( pTable->Lower() ) 2627 { 2628 if ( pTable->IsFollow() ) 2629 { 2630 lcl_UpdateRepeatedHeadlines( *pTable, true ); 2631 } 2632 2633 ASSERT( ((SwRowFrm*)pTable->Lower())->GetTabLine() == 2634 rTable.GetTabLines()[0], "MakeNewFrms: Table corruption!" ) 2635 } 2636 } 2637 } 2638 } 2639 2640 sal_Bool _FndBox::AreLinesToRestore( const SwTable &rTable ) const 2641 { 2642 //Lohnt es sich MakeFrms zu rufen? 2643 2644 if ( !pLineBefore && !pLineBehind && rTable.GetTabLines().Count() ) 2645 return sal_True; 2646 2647 sal_uInt16 nBfPos; 2648 if(pLineBefore) 2649 { 2650 const SwTableLine* rLBefore = (const SwTableLine*)pLineBefore; 2651 nBfPos = rTable.GetTabLines().GetPos( rLBefore ); 2652 } 2653 else 2654 nBfPos = USHRT_MAX; 2655 2656 sal_uInt16 nBhPos; 2657 if(pLineBehind) 2658 { 2659 const SwTableLine* rLBehind = (const SwTableLine*)pLineBehind; 2660 nBhPos = rTable.GetTabLines().GetPos( rLBehind ); 2661 } 2662 else 2663 nBhPos = USHRT_MAX; 2664 2665 if ( nBfPos == nBhPos ) //Duerfte eigentlich nie vorkommen. 2666 { 2667 ASSERT( sal_False, "Table, Loeschen auf keinem Bereich !?!" ); 2668 return sal_False; 2669 } 2670 2671 if ( rTable.GetRowsToRepeat() > 0 ) 2672 { 2673 // ups. sollte unsere zu wiederholende Kopfzeile geloescht worden 2674 // sein?? 2675 SwIterator<SwTabFrm,SwFmt> aIter( *rTable.GetFrmFmt() ); 2676 for( SwTabFrm* pTable = aIter.First(); pTable; pTable = aIter.Next() ) 2677 { 2678 if( pTable->IsFollow() ) 2679 { 2680 // Insert new headlines: 2681 lcl_UpdateRepeatedHeadlines( *pTable, false ); 2682 } 2683 } 2684 } 2685 2686 // Some adjacent lines at the beginning of the table have been deleted: 2687 if ( nBfPos == USHRT_MAX && nBhPos == 0 ) 2688 return sal_False; 2689 2690 // Some adjacent lines at the end of the table have been deleted: 2691 if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().Count() - 1) ) 2692 return sal_False; 2693 2694 // Some adjacent lines in the middle of the table have been deleted: 2695 if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos ) 2696 return sal_False; 2697 2698 // The structure of the deleted lines is more complex due to split lines. 2699 // A call of MakeFrms() is necessary. 2700 return sal_True; 2701 } 2702 2703 2704