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_sc.hxx" 26 27 // INCLUDE --------------------------------------------------------------- 28 29 #include "scitems.hxx" 30 #include <svx/algitem.hxx> 31 #include <unotools/textsearch.hxx> 32 #include <sfx2/objsh.hxx> 33 34 #include "attrib.hxx" 35 #include "patattr.hxx" 36 #include "cell.hxx" 37 #include "table.hxx" 38 #include "document.hxx" 39 #include "drwlayer.hxx" 40 #include "olinetab.hxx" 41 #include "stlsheet.hxx" 42 #include "global.hxx" 43 #include "globstr.hrc" 44 #include "refupdat.hxx" 45 #include "markdata.hxx" 46 #include "progress.hxx" 47 #include "hints.hxx" // fuer Paint-Broadcast 48 #include "prnsave.hxx" 49 #include "tabprotection.hxx" 50 #include "sheetevents.hxx" 51 #include "segmenttree.hxx" 52 53 // ----------------------------------------------------------------------- 54 55 ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const String& rNewName, 56 sal_Bool bColInfo, sal_Bool bRowInfo ) : 57 aName( rNewName ), 58 aCodeName( rNewName ), 59 bScenario( sal_False ), 60 bLayoutRTL( sal_False ), 61 bLoadingRTL( sal_False ), 62 nLinkMode( 0 ), 63 aPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) ), 64 bPageSizeValid( sal_False ), 65 nRepeatStartX( SCCOL_REPEAT_NONE ), 66 nRepeatStartY( SCROW_REPEAT_NONE ), 67 pTabProtection( NULL ), 68 pColWidth( NULL ), 69 mpRowHeights( static_cast<ScFlatUInt16RowSegments*>(NULL) ), 70 pColFlags( NULL ), 71 pRowFlags( NULL ), 72 mpHiddenCols(new ScFlatBoolColSegments), 73 mpHiddenRows(new ScFlatBoolRowSegments), 74 mpFilteredCols(new ScFlatBoolColSegments), 75 mpFilteredRows(new ScFlatBoolRowSegments), 76 pOutlineTable( NULL ), 77 pSheetEvents( NULL ), 78 bTableAreaValid( sal_False ), 79 bVisible( sal_True ), 80 bStreamValid( sal_False ), 81 bPendingRowHeights( sal_False ), 82 bCalcNotification( sal_False ), 83 nTab( nNewTab ), 84 nRecalcLvl( 0 ), 85 pDocument( pDoc ), 86 pSearchParam( NULL ), 87 pSearchText ( NULL ), 88 pSortCollator( NULL ), 89 bPrintEntireSheet( sal_False ), 90 pRepeatColRange( NULL ), 91 pRepeatRowRange( NULL ), 92 nLockCount( 0 ), 93 pScenarioRanges( NULL ), 94 aScenarioColor( COL_LIGHTGRAY ), 95 aTabBgColor( COL_AUTO ), 96 nScenarioFlags( 0 ), 97 bActiveScenario( sal_False ), 98 mbPageBreaksValid(false) 99 { 100 101 if (bColInfo) 102 { 103 pColWidth = new sal_uInt16[ MAXCOL+1 ]; 104 pColFlags = new sal_uInt8[ MAXCOL+1 ]; 105 106 for (SCCOL i=0; i<=MAXCOL; i++) 107 { 108 pColWidth[i] = STD_COL_WIDTH; 109 pColFlags[i] = 0; 110 } 111 } 112 113 if (bRowInfo) 114 { 115 mpRowHeights.reset(new ScFlatUInt16RowSegments(ScGlobal::nStdRowHeight)); 116 pRowFlags = new ScBitMaskCompressedArray< SCROW, sal_uInt8>( MAXROW, 0); 117 } 118 119 if ( pDocument->IsDocVisible() ) 120 { 121 // when a sheet is added to a visible document, 122 // initialize its RTL flag from the system locale 123 bLayoutRTL = ScGlobal::IsSystemRTL(); 124 } 125 126 ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer(); 127 if (pDrawLayer) 128 { 129 if ( pDrawLayer->ScAddPage( nTab ) ) // sal_False (not inserted) during Undo 130 { 131 pDrawLayer->ScRenamePage( nTab, aName ); 132 sal_uLong nx = (sal_uLong) ((double) (MAXCOL+1) * STD_COL_WIDTH * HMM_PER_TWIPS ); 133 sal_uLong ny = (sal_uLong) ((double) (MAXROW+1) * ScGlobal::nStdRowHeight * HMM_PER_TWIPS ); 134 pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( nx, ny ), false ); 135 } 136 } 137 138 for (SCCOL k=0; k<=MAXCOL; k++) 139 aCol[k].Init( k, nTab, pDocument ); 140 } 141 142 ScTable::~ScTable() 143 { 144 if (!pDocument->IsInDtorClear()) 145 { 146 // nicht im dtor die Pages in der falschen Reihenfolge loeschen 147 // (nTab stimmt dann als Page-Number nicht!) 148 // In ScDocument::Clear wird hinterher per Clear am Draw Layer alles geloescht. 149 150 ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer(); 151 if (pDrawLayer) 152 pDrawLayer->ScRemovePage( nTab ); 153 } 154 155 delete[] pColWidth; 156 delete[] pColFlags; 157 delete pRowFlags; 158 delete pSheetEvents; 159 delete pOutlineTable; 160 delete pSearchParam; 161 delete pSearchText; 162 delete pRepeatColRange; 163 delete pRepeatRowRange; 164 delete pScenarioRanges; 165 DestroySortCollator(); 166 } 167 168 void ScTable::GetName( String& rName ) const 169 { 170 rName = aName; 171 } 172 173 void ScTable::SetName( const String& rNewName ) 174 { 175 aName = rNewName; 176 aUpperName.Erase(); // invalidated if the name is changed 177 178 // SetStreamValid is handled in ScDocument::RenameTab 179 } 180 181 const String& ScTable::GetUpperName() const 182 { 183 if ( !aUpperName.Len() && aName.Len() ) 184 aUpperName = ScGlobal::pCharClass->upper( aName ); 185 return aUpperName; 186 } 187 188 void ScTable::SetVisible( sal_Bool bVis ) 189 { 190 if (bVisible != bVis && IsStreamValid()) 191 SetStreamValid(sal_False); 192 193 bVisible = bVis; 194 } 195 196 void ScTable::SetStreamValid( sal_Bool bSet, sal_Bool bIgnoreLock ) 197 { 198 if ( bIgnoreLock || !pDocument->IsStreamValidLocked() ) 199 bStreamValid = bSet; 200 } 201 202 void ScTable::SetPendingRowHeights( sal_Bool bSet ) 203 { 204 bPendingRowHeights = bSet; 205 } 206 207 void ScTable::SetLayoutRTL( sal_Bool bSet ) 208 { 209 bLayoutRTL = bSet; 210 } 211 212 void ScTable::SetLoadingRTL( sal_Bool bSet ) 213 { 214 bLoadingRTL = bSet; 215 } 216 217 const Color& ScTable::GetTabBgColor() const 218 { 219 return aTabBgColor; 220 } 221 222 void ScTable::SetTabBgColor(const Color& rColor) 223 { 224 if (aTabBgColor != rColor) 225 { 226 // The tab color has changed. Set this table 'modified'. 227 aTabBgColor = rColor; 228 if (IsStreamValid()) 229 SetStreamValid(false); 230 } 231 } 232 233 void ScTable::SetScenario( sal_Bool bFlag ) 234 { 235 bScenario = bFlag; 236 } 237 238 void ScTable::SetLink( sal_uInt8 nMode, 239 const String& rDoc, const String& rFlt, const String& rOpt, 240 const String& rTab, sal_uLong nRefreshDelay ) 241 { 242 nLinkMode = nMode; 243 aLinkDoc = rDoc; // Datei 244 aLinkFlt = rFlt; // Filter 245 aLinkOpt = rOpt; // Filter-Optionen 246 aLinkTab = rTab; // Tabellenname in Quelldatei 247 nLinkRefreshDelay = nRefreshDelay; // refresh delay in seconds, 0==off 248 249 if (IsStreamValid()) 250 SetStreamValid(sal_False); 251 } 252 253 sal_uInt16 ScTable::GetOptimalColWidth( SCCOL nCol, OutputDevice* pDev, 254 double nPPTX, double nPPTY, 255 const Fraction& rZoomX, const Fraction& rZoomY, 256 sal_Bool bFormula, const ScMarkData* pMarkData, 257 sal_Bool bSimpleTextImport ) 258 { 259 return aCol[nCol].GetOptimalColWidth( pDev, nPPTX, nPPTY, rZoomX, rZoomY, 260 bFormula, STD_COL_WIDTH - STD_EXTRA_WIDTH, pMarkData, bSimpleTextImport ); 261 } 262 263 long ScTable::GetNeededSize( SCCOL nCol, SCROW nRow, 264 OutputDevice* pDev, 265 double nPPTX, double nPPTY, 266 const Fraction& rZoomX, const Fraction& rZoomY, 267 sal_Bool bWidth, sal_Bool bTotalSize ) 268 { 269 ScNeededSizeOptions aOptions; 270 aOptions.bSkipMerged = sal_False; // zusammengefasste mitzaehlen 271 aOptions.bTotalSize = bTotalSize; 272 273 return aCol[nCol].GetNeededSize 274 ( nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, aOptions ); 275 } 276 277 sal_Bool ScTable::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, sal_uInt16 nExtra, 278 OutputDevice* pDev, 279 double nPPTX, double nPPTY, 280 const Fraction& rZoomX, const Fraction& rZoomY, 281 sal_Bool bForce, ScProgress* pOuterProgress, sal_uLong nProgressStart ) 282 { 283 DBG_ASSERT( nExtra==0 || bForce, "autom. OptimalHeight mit Extra" ); 284 285 if ( !pDocument->IsAdjustHeightEnabled() ) 286 { 287 return sal_False; 288 } 289 290 sal_Bool bChanged = sal_False; 291 SCSIZE nCount = static_cast<SCSIZE>(nEndRow-nStartRow+1); 292 293 ScProgress* pProgress = NULL; 294 if ( pOuterProgress ) 295 pProgress = pOuterProgress; 296 else if ( nCount > 1 ) 297 pProgress = new ScProgress( pDocument->GetDocumentShell(), 298 ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), GetWeightedCount() ); 299 300 sal_uInt16* pHeight = new sal_uInt16[nCount]; // Twips ! 301 memset( pHeight, 0, sizeof(sal_uInt16) * nCount ); 302 303 // zuerst einmal ueber den ganzen Bereich 304 // (mit der letzten Spalte in der Hoffnung, dass die am ehesten noch auf 305 // Standard formatiert ist) 306 307 aCol[MAXCOL].GetOptimalHeight( 308 nStartRow, nEndRow, pHeight, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce, 0, 0 ); 309 310 // daraus Standardhoehe suchen, die im unteren Bereich gilt 311 312 sal_uInt16 nMinHeight = pHeight[nCount-1]; 313 SCSIZE nPos = nCount-1; 314 while ( nPos && pHeight[nPos-1] >= nMinHeight ) 315 --nPos; 316 SCROW nMinStart = nStartRow + nPos; 317 318 sal_uLong nWeightedCount = 0; 319 for (SCCOL nCol=0; nCol<MAXCOL; nCol++) // MAXCOL schon oben 320 { 321 aCol[nCol].GetOptimalHeight( 322 nStartRow, nEndRow, pHeight, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce, 323 nMinHeight, nMinStart ); 324 325 if (pProgress) 326 { 327 sal_uLong nWeight = aCol[nCol].GetWeightedCount(); 328 if (nWeight) // nochmal denselben Status muss auch nicht sein 329 { 330 nWeightedCount += nWeight; 331 pProgress->SetState( nWeightedCount + nProgressStart ); 332 } 333 } 334 } 335 336 IncRecalcLevel(); // #i116460# avoid problems with Excel files 337 338 SCROW nRngStart = 0; 339 SCROW nRngEnd = 0; 340 sal_uInt16 nLast = 0; 341 for (SCSIZE i=0; i<nCount; i++) 342 { 343 size_t nIndex; 344 SCROW nRegionEndRow; 345 sal_uInt8 nRowFlag = pRowFlags->GetValue( nStartRow+i, nIndex, nRegionEndRow ); 346 if ( nRegionEndRow > nEndRow ) 347 nRegionEndRow = nEndRow; 348 SCSIZE nMoreRows = nRegionEndRow - ( nStartRow+i ); // additional equal rows after first 349 350 bool bAutoSize = ((nRowFlag & CR_MANUALSIZE) == 0); 351 if ( bAutoSize || bForce ) 352 { 353 if (nExtra) 354 { 355 if (bAutoSize) 356 pRowFlags->SetValue( nStartRow+i, nRegionEndRow, nRowFlag | CR_MANUALSIZE); 357 } 358 else if (!bAutoSize) 359 pRowFlags->SetValue( nStartRow+i, nRegionEndRow, nRowFlag & ~CR_MANUALSIZE); 360 361 for (SCSIZE nInner = i; nInner <= i + nMoreRows; ++nInner) 362 { 363 if (nLast) 364 { 365 if (pHeight[nInner]+nExtra == nLast) 366 nRngEnd = nStartRow+nInner; 367 else 368 { 369 bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY ); 370 nLast = 0; 371 } 372 } 373 if (!nLast) 374 { 375 nLast = pHeight[nInner]+nExtra; 376 nRngStart = nStartRow+nInner; 377 nRngEnd = nStartRow+nInner; 378 } 379 } 380 } 381 else 382 { 383 if (nLast) 384 bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY ); 385 nLast = 0; 386 } 387 i += nMoreRows; // already handled - skip 388 } 389 if (nLast) 390 bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY ); 391 392 DecRecalcLevel(); // #i116460# avoid problems with Excel files 393 394 delete[] pHeight; 395 if ( pProgress != pOuterProgress ) 396 delete pProgress; 397 398 return bChanged; 399 } 400 401 sal_Bool ScTable::GetCellArea( SCCOL& rEndCol, SCROW& rEndRow ) const 402 { 403 sal_Bool bFound = sal_False; 404 SCCOL nMaxX = 0; 405 SCROW nMaxY = 0; 406 for (SCCOL i=0; i<=MAXCOL; i++) 407 if (!aCol[i].IsEmptyVisData(sal_True)) // sal_True = Notizen zaehlen auch 408 { 409 bFound = sal_True; 410 nMaxX = i; 411 SCROW nColY = aCol[i].GetLastVisDataPos(sal_True); 412 if (nColY > nMaxY) 413 nMaxY = nColY; 414 } 415 416 rEndCol = nMaxX; 417 rEndRow = nMaxY; 418 return bFound; 419 } 420 421 sal_Bool ScTable::GetTableArea( SCCOL& rEndCol, SCROW& rEndRow ) const 422 { 423 sal_Bool bRet = sal_True; //! merken? 424 if (!bTableAreaValid) 425 { 426 bRet = GetPrintArea( ((ScTable*)this)->nTableAreaX, 427 ((ScTable*)this)->nTableAreaY, sal_True ); 428 ((ScTable*)this)->bTableAreaValid = sal_True; 429 } 430 rEndCol = nTableAreaX; 431 rEndRow = nTableAreaY; 432 return bRet; 433 } 434 435 /* vorher: 436 437 sal_Bool bFound = sal_False; 438 SCCOL nMaxX = 0; 439 SCROW nMaxY = 0; 440 for (SCCOL i=0; i<=MAXCOL; i++) 441 if (!aCol[i].IsEmpty()) 442 { 443 bFound = sal_True; 444 nMaxX = i; 445 SCCOL nColY = aCol[i].GetLastEntryPos(); 446 if (nColY > nMaxY) 447 nMaxY = nColY; 448 } 449 450 rEndCol = nMaxX; 451 rEndRow = nMaxY; 452 return bFound; 453 */ 454 455 const SCCOL SC_COLUMNS_STOP = 30; 456 457 sal_Bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, sal_Bool bNotes ) const 458 { 459 sal_Bool bFound = sal_False; 460 SCCOL nMaxX = 0; 461 SCROW nMaxY = 0; 462 SCCOL i; 463 464 for (i=0; i<=MAXCOL; i++) // Daten testen 465 if (!aCol[i].IsEmptyVisData(bNotes)) 466 { 467 bFound = sal_True; 468 if (i>nMaxX) 469 nMaxX = i; 470 SCROW nColY = aCol[i].GetLastVisDataPos(bNotes); 471 if (nColY > nMaxY) 472 nMaxY = nColY; 473 } 474 475 SCCOL nMaxDataX = nMaxX; 476 477 for (i=0; i<=MAXCOL; i++) // Attribute testen 478 { 479 SCROW nLastRow; 480 if (aCol[i].GetLastVisibleAttr( nLastRow )) 481 { 482 bFound = sal_True; 483 nMaxX = i; 484 if (nLastRow > nMaxY) 485 nMaxY = nLastRow; 486 } 487 } 488 489 if (nMaxX == MAXCOL) // Attribute rechts weglassen 490 { 491 --nMaxX; 492 while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1]) ) 493 --nMaxX; 494 } 495 496 if ( nMaxX < nMaxDataX ) 497 { 498 nMaxX = nMaxDataX; 499 } 500 else if ( nMaxX > nMaxDataX ) 501 { 502 SCCOL nAttrStartX = nMaxDataX + 1; 503 while ( nAttrStartX < MAXCOL ) 504 { 505 SCCOL nAttrEndX = nAttrStartX; 506 while ( nAttrEndX < MAXCOL && aCol[nAttrStartX].IsVisibleAttrEqual(aCol[nAttrEndX+1]) ) 507 ++nAttrEndX; 508 if ( nAttrEndX + 1 - nAttrStartX >= SC_COLUMNS_STOP ) 509 { 510 // found equally-formatted columns behind data -> stop before these columns 511 nMaxX = nAttrStartX - 1; 512 513 // also don't include default-formatted columns before that 514 SCROW nDummyRow; 515 while ( nMaxX > nMaxDataX && !aCol[nMaxX].GetLastVisibleAttr( nDummyRow ) ) 516 --nMaxX; 517 break; 518 } 519 nAttrStartX = nAttrEndX + 1; 520 } 521 } 522 523 rEndCol = nMaxX; 524 rEndRow = nMaxY; 525 return bFound; 526 } 527 528 sal_Bool ScTable::GetPrintAreaHor( SCROW nStartRow, SCROW nEndRow, 529 SCCOL& rEndCol, sal_Bool /* bNotes */ ) const 530 { 531 sal_Bool bFound = sal_False; 532 SCCOL nMaxX = 0; 533 SCCOL i; 534 535 for (i=0; i<=MAXCOL; i++) // Attribute testen 536 { 537 if (aCol[i].HasVisibleAttrIn( nStartRow, nEndRow )) 538 { 539 bFound = sal_True; 540 nMaxX = i; 541 } 542 } 543 544 if (nMaxX == MAXCOL) // Attribute rechts weglassen 545 { 546 --nMaxX; 547 while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1], nStartRow, nEndRow) ) 548 --nMaxX; 549 } 550 551 for (i=0; i<=MAXCOL; i++) // Daten testen 552 { 553 if (!aCol[i].IsEmptyBlock( nStartRow, nEndRow )) //! bNotes ?????? 554 { 555 bFound = sal_True; 556 if (i>nMaxX) 557 nMaxX = i; 558 } 559 } 560 561 rEndCol = nMaxX; 562 return bFound; 563 } 564 565 sal_Bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol, 566 SCROW& rEndRow, sal_Bool bNotes ) const 567 { 568 sal_Bool bFound = sal_False; 569 SCROW nMaxY = 0; 570 SCCOL i; 571 572 for (i=nStartCol; i<=nEndCol; i++) // Attribute testen 573 { 574 SCROW nLastRow; 575 if (aCol[i].GetLastVisibleAttr( nLastRow )) 576 { 577 bFound = sal_True; 578 if (nLastRow > nMaxY) 579 nMaxY = nLastRow; 580 } 581 } 582 583 for (i=nStartCol; i<=nEndCol; i++) // Daten testen 584 if (!aCol[i].IsEmptyVisData(bNotes)) 585 { 586 bFound = sal_True; 587 SCROW nColY = aCol[i].GetLastVisDataPos(bNotes); 588 if (nColY > nMaxY) 589 nMaxY = nColY; 590 } 591 592 rEndRow = nMaxY; 593 return bFound; 594 } 595 596 sal_Bool ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const 597 { 598 sal_Bool bFound = sal_False; 599 SCCOL nMinX = MAXCOL; 600 SCROW nMinY = MAXROW; 601 SCCOL i; 602 603 for (i=0; i<=MAXCOL; i++) // Attribute testen 604 { 605 SCROW nFirstRow; 606 if (aCol[i].GetFirstVisibleAttr( nFirstRow )) 607 { 608 if (!bFound) 609 nMinX = i; 610 bFound = sal_True; 611 if (nFirstRow < nMinY) 612 nMinY = nFirstRow; 613 } 614 } 615 616 if (nMinX == 0) // Attribute links weglassen 617 { 618 if ( aCol[0].IsVisibleAttrEqual(aCol[1]) ) // keine einzelnen 619 { 620 ++nMinX; 621 while ( nMinX<MAXCOL && aCol[nMinX].IsVisibleAttrEqual(aCol[nMinX-1]) ) 622 ++nMinX; 623 } 624 } 625 626 sal_Bool bDatFound = sal_False; 627 for (i=0; i<=MAXCOL; i++) // Daten testen 628 if (!aCol[i].IsEmptyVisData(sal_True)) 629 { 630 if (!bDatFound && i<nMinX) 631 nMinX = i; 632 bFound = bDatFound = sal_True; 633 SCROW nColY = aCol[i].GetFirstVisDataPos(sal_True); 634 if (nColY < nMinY) 635 nMinY = nColY; 636 } 637 638 rStartCol = nMinX; 639 rStartRow = nMinY; 640 return bFound; 641 } 642 643 void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, 644 sal_Bool bIncludeOld, bool bOnlyDown ) const 645 { 646 sal_Bool bLeft = sal_False; 647 sal_Bool bRight = sal_False; 648 sal_Bool bTop = sal_False; 649 sal_Bool bBottom = sal_False; 650 sal_Bool bChanged; 651 sal_Bool bFound; 652 SCCOL i; 653 SCROW nTest; 654 655 do 656 { 657 bChanged = sal_False; 658 659 if (!bOnlyDown) 660 { 661 SCROW nStart = rStartRow; 662 SCROW nEnd = rEndRow; 663 if (nStart>0) --nStart; 664 if (nEnd<MAXROW) ++nEnd; 665 666 if (rEndCol < MAXCOL) 667 if (!aCol[rEndCol+1].IsEmptyBlock(nStart,nEnd)) 668 { 669 ++rEndCol; 670 bChanged = sal_True; 671 bRight = sal_True; 672 } 673 674 if (rStartCol > 0) 675 if (!aCol[rStartCol-1].IsEmptyBlock(nStart,nEnd)) 676 { 677 --rStartCol; 678 bChanged = sal_True; 679 bLeft = sal_True; 680 } 681 682 if (rStartRow > 0) 683 { 684 nTest = rStartRow-1; 685 bFound = sal_False; 686 for (i=rStartCol; i<=rEndCol && !bFound; i++) 687 if (aCol[i].HasDataAt(nTest)) 688 bFound = sal_True; 689 if (bFound) 690 { 691 --rStartRow; 692 bChanged = sal_True; 693 bTop = sal_True; 694 } 695 } 696 } 697 698 if (rEndRow < MAXROW) 699 { 700 nTest = rEndRow+1; 701 bFound = sal_False; 702 for (i=rStartCol; i<=rEndCol && !bFound; i++) 703 if (aCol[i].HasDataAt(nTest)) 704 bFound = sal_True; 705 if (bFound) 706 { 707 ++rEndRow; 708 bChanged = sal_True; 709 bBottom = sal_True; 710 } 711 } 712 } 713 while( bChanged ); 714 715 if ( !bIncludeOld ) 716 { 717 if ( !bLeft && rStartCol < MAXCOL && rStartCol < rEndCol ) 718 if ( aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) ) 719 ++rStartCol; 720 if ( !bRight && rEndCol > 0 && rStartCol < rEndCol ) 721 if ( aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) ) 722 --rEndCol; 723 if ( !bTop && rStartRow < MAXROW && rStartRow < rEndRow ) 724 { 725 bFound = sal_False; 726 for (i=rStartCol; i<=rEndCol && !bFound; i++) 727 if (aCol[i].HasDataAt(rStartRow)) 728 bFound = sal_True; 729 if (!bFound) 730 ++rStartRow; 731 } 732 if ( !bBottom && rEndRow > 0 && rStartRow < rEndRow ) 733 { 734 bFound = sal_False; 735 for (i=rStartCol; i<=rEndCol && !bFound; i++) 736 if (aCol[i].HasDataAt(rEndRow)) 737 bFound = sal_True; 738 if (!bFound) 739 --rEndRow; 740 } 741 } 742 } 743 744 745 bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow, 746 SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const 747 { 748 o_bShrunk = false; 749 750 PutInOrder( rStartCol, rEndCol); 751 PutInOrder( rStartRow, rEndRow); 752 if (rStartCol < 0) 753 rStartCol = 0, o_bShrunk = true; 754 if (rStartRow < 0) 755 rStartRow = 0, o_bShrunk = true; 756 if (rEndCol > MAXCOL) 757 rEndCol = MAXCOL, o_bShrunk = true; 758 if (rEndRow > MAXROW) 759 rEndRow = MAXROW, o_bShrunk = true; 760 761 bool bChanged; 762 do 763 { 764 bChanged = false; 765 766 while (rStartCol < rEndCol) 767 { 768 if (aCol[rEndCol].IsEmptyBlock( rStartRow, rEndRow)) 769 { 770 --rEndCol; 771 bChanged = true; 772 } 773 else 774 break; // while 775 } 776 777 while (rStartCol < rEndCol) 778 { 779 if (aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow)) 780 { 781 ++rStartCol; 782 bChanged = true; 783 } 784 else 785 break; // while 786 } 787 788 if (!bColumnsOnly) 789 { 790 if (rStartRow < rEndRow) 791 { 792 bool bFound = false; 793 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++) 794 if (aCol[i].HasDataAt( rStartRow)) 795 bFound = true; 796 if (!bFound) 797 { 798 ++rStartRow; 799 bChanged = true; 800 } 801 } 802 803 if (rStartRow < rEndRow) 804 { 805 bool bFound = false; 806 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++) 807 if (aCol[i].HasDataAt( rEndRow)) 808 bFound = true; 809 if (!bFound) 810 { 811 --rEndRow; 812 bChanged = true; 813 } 814 } 815 } 816 817 if (bChanged) 818 o_bShrunk = true; 819 } while( bChanged ); 820 821 return rStartCol != rEndCol || (bColumnsOnly ? 822 !aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow) : 823 (rStartRow != rEndRow || aCol[rStartCol].HasDataAt( rStartRow))); 824 } 825 826 827 SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, 828 SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) 829 { 830 SCSIZE nCount = 0; 831 SCCOL nCol; 832 if ((eDir == DIR_BOTTOM) || (eDir == DIR_TOP)) 833 { 834 nCount = static_cast<SCSIZE>(nEndRow - nStartRow); 835 for (nCol = nStartCol; nCol <= nEndCol; nCol++) 836 nCount = Min(nCount, aCol[nCol].GetEmptyLinesInBlock(nStartRow, nEndRow, eDir)); 837 } 838 else if (eDir == DIR_RIGHT) 839 { 840 nCol = nEndCol; 841 while (((SCsCOL)nCol >= (SCsCOL)nStartCol) && 842 aCol[nCol].IsEmptyBlock(nStartRow, nEndRow)) 843 { 844 nCount++; 845 nCol--; 846 } 847 } 848 else 849 { 850 nCol = nStartCol; 851 while ((nCol <= nEndCol) && aCol[nCol].IsEmptyBlock(nStartRow, nEndRow)) 852 { 853 nCount++; 854 nCol++; 855 } 856 } 857 return nCount; 858 } 859 860 sal_Bool ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, SCCOL nEndCol ) 861 { 862 sal_Bool bFound = sal_False; 863 for (SCCOL i=nStartCol; i<=nEndCol && !bFound; i++) 864 if (aCol[i].HasDataAt(nRow)) 865 bFound = sal_True; 866 return !bFound; 867 } 868 869 void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow ) 870 { 871 while ( rStartCol<rEndCol && aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) ) 872 ++rStartCol; 873 874 while ( rStartCol<rEndCol && aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) ) 875 --rEndCol; 876 877 while ( rStartRow<rEndRow && IsEmptyLine(rStartRow, rStartCol, rEndCol) ) 878 ++rStartRow; 879 880 while ( rStartRow<rEndRow && IsEmptyLine(rEndRow, rStartCol, rEndCol) ) 881 --rEndRow; 882 } 883 884 void ScTable::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY ) 885 { 886 if (nMovX) 887 { 888 SCsCOL nNewCol = (SCsCOL) rCol; 889 sal_Bool bThere = aCol[nNewCol].HasVisibleDataAt(rRow); 890 sal_Bool bFnd; 891 if (bThere) 892 { 893 do 894 { 895 nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX ); 896 bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : sal_False; 897 } 898 while (bFnd); 899 nNewCol = sal::static_int_cast<SCsCOL>( nNewCol - nMovX ); 900 901 if (nNewCol == (SCsCOL)rCol) 902 bThere = sal_False; 903 } 904 905 if (!bThere) 906 { 907 do 908 { 909 nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX ); 910 bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : sal_True; 911 } 912 while (!bFnd); 913 } 914 915 if (nNewCol<0) nNewCol=0; 916 if (nNewCol>MAXCOL) nNewCol=MAXCOL; 917 rCol = (SCCOL) nNewCol; 918 } 919 920 if (nMovY) 921 aCol[rCol].FindDataAreaPos(rRow,nMovY); 922 } 923 924 sal_Bool ScTable::ValidNextPos( SCCOL nCol, SCROW nRow, const ScMarkData& rMark, 925 sal_Bool bMarked, sal_Bool bUnprotected ) 926 { 927 if (!ValidCol(nCol) || !ValidRow(nRow)) 928 return sal_False; 929 930 if (pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) 931 // Skip an overlapped cell. 932 return false; 933 934 if (bMarked && !rMark.IsCellMarked(nCol,nRow)) 935 return sal_False; 936 937 if (bUnprotected && ((const ScProtectionAttr*) 938 GetAttr(nCol,nRow,ATTR_PROTECTION))->GetProtection()) 939 return sal_False; 940 941 if (bMarked || bUnprotected) //! auch sonst ??? 942 { 943 // #53697# ausgeblendete muessen uebersprungen werden, weil der Cursor sonst 944 // auf der naechsten Zelle landet, auch wenn die geschuetzt/nicht markiert ist. 945 //! per Extra-Parameter steuern, nur fuer Cursor-Bewegung ??? 946 947 if (RowHidden(nRow)) 948 return sal_False; 949 950 if (ColHidden(nCol)) 951 return sal_False; 952 } 953 954 return sal_True; 955 } 956 957 void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY, 958 sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark ) 959 { 960 if (bUnprotected && !IsProtected()) // Tabelle ueberhaupt geschuetzt? 961 bUnprotected = sal_False; 962 963 sal_uInt16 nWrap = 0; 964 SCsCOL nCol = rCol; 965 SCsROW nRow = rRow; 966 967 nCol = sal::static_int_cast<SCsCOL>( nCol + nMovX ); 968 nRow = sal::static_int_cast<SCsROW>( nRow + nMovY ); 969 970 DBG_ASSERT( !nMovY || !bUnprotected, 971 "GetNextPos mit bUnprotected horizontal nicht implementiert" ); 972 973 if ( nMovY && bMarked ) 974 { 975 sal_Bool bUp = ( nMovY < 0 ); 976 nRow = rMark.GetNextMarked( nCol, nRow, bUp ); 977 while ( VALIDROW(nRow) && 978 (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) ) 979 { 980 // #53697# ausgeblendete ueberspringen (s.o.) 981 nRow += nMovY; 982 nRow = rMark.GetNextMarked( nCol, nRow, bUp ); 983 } 984 985 while ( nRow < 0 || nRow > MAXROW ) 986 { 987 nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) ); 988 while ( VALIDCOL(nCol) && ColHidden(nCol) ) 989 nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) ); // #53697# skip hidden rows (see above) 990 if (nCol < 0) 991 { 992 nCol = MAXCOL; 993 if (++nWrap >= 2) 994 return; 995 } 996 else if (nCol > MAXCOL) 997 { 998 nCol = 0; 999 if (++nWrap >= 2) 1000 return; 1001 } 1002 if (nRow < 0) 1003 nRow = MAXROW; 1004 else if (nRow > MAXROW) 1005 nRow = 0; 1006 nRow = rMark.GetNextMarked( nCol, nRow, bUp ); 1007 while ( VALIDROW(nRow) && 1008 (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) ) 1009 { 1010 // #53697# ausgeblendete ueberspringen (s.o.) 1011 nRow += nMovY; 1012 nRow = rMark.GetNextMarked( nCol, nRow, bUp ); 1013 } 1014 } 1015 } 1016 1017 if ( nMovX && ( bMarked || bUnprotected ) ) 1018 { 1019 // initiales Weiterzaehlen wrappen: 1020 if (nCol<0) 1021 { 1022 nCol = MAXCOL; 1023 --nRow; 1024 if (nRow<0) 1025 nRow = MAXROW; 1026 } 1027 if (nCol>MAXCOL) 1028 { 1029 nCol = 0; 1030 ++nRow; 1031 if (nRow>MAXROW) 1032 nRow = 0; 1033 } 1034 1035 if ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) ) 1036 { 1037 SCsROW* pNextRows = new SCsROW[MAXCOL+1]; 1038 SCCOL i; 1039 1040 if ( nMovX > 0 ) // vorwaerts 1041 { 1042 for (i=0; i<=MAXCOL; i++) 1043 pNextRows[i] = (i<nCol) ? (nRow+1) : nRow; 1044 do 1045 { 1046 SCsROW nNextRow = pNextRows[nCol] + 1; 1047 if ( bMarked ) 1048 nNextRow = rMark.GetNextMarked( nCol, nNextRow, sal_False ); 1049 if ( bUnprotected ) 1050 nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_False ); 1051 pNextRows[nCol] = nNextRow; 1052 1053 SCsROW nMinRow = MAXROW+1; 1054 for (i=0; i<=MAXCOL; i++) 1055 if (pNextRows[i] < nMinRow) // bei gleichen den linken 1056 { 1057 nMinRow = pNextRows[i]; 1058 nCol = i; 1059 } 1060 nRow = nMinRow; 1061 1062 if ( nRow > MAXROW ) 1063 { 1064 if (++nWrap >= 2) break; // ungueltigen Wert behalten 1065 nCol = 0; 1066 nRow = 0; 1067 for (i=0; i<=MAXCOL; i++) 1068 pNextRows[i] = 0; // alles ganz von vorne 1069 } 1070 } 1071 while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) ); 1072 } 1073 else // rueckwaerts 1074 { 1075 for (i=0; i<=MAXCOL; i++) 1076 pNextRows[i] = (i>nCol) ? (nRow-1) : nRow; 1077 do 1078 { 1079 SCsROW nNextRow = pNextRows[nCol] - 1; 1080 if ( bMarked ) 1081 nNextRow = rMark.GetNextMarked( nCol, nNextRow, sal_True ); 1082 if ( bUnprotected ) 1083 nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_True ); 1084 pNextRows[nCol] = nNextRow; 1085 1086 SCsROW nMaxRow = -1; 1087 for (i=0; i<=MAXCOL; i++) 1088 if (pNextRows[i] >= nMaxRow) // bei gleichen den rechten 1089 { 1090 nMaxRow = pNextRows[i]; 1091 nCol = i; 1092 } 1093 nRow = nMaxRow; 1094 1095 if ( nRow < 0 ) 1096 { 1097 if (++nWrap >= 2) break; // ungueltigen Wert behalten 1098 nCol = MAXCOL; 1099 nRow = MAXROW; 1100 for (i=0; i<=MAXCOL; i++) 1101 pNextRows[i] = MAXROW; // alles ganz von vorne 1102 } 1103 } 1104 while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) ); 1105 } 1106 1107 delete[] pNextRows; 1108 } 1109 } 1110 1111 // ungueltige Werte kommen z.b. bei Tab heraus, 1112 // wenn nicht markiert und nicht geschuetzt ist (linker / rechter Rand), 1113 // dann Werte unveraendert lassen 1114 1115 if (VALIDCOLROW(nCol,nRow)) 1116 { 1117 rCol = nCol; 1118 rRow = nRow; 1119 } 1120 } 1121 1122 sal_Bool ScTable::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark ) 1123 { 1124 const ScMarkArray* pMarkArray = rMark.GetArray(); 1125 DBG_ASSERT(pMarkArray,"GetNextMarkedCell ohne MarkArray"); 1126 if ( !pMarkArray ) 1127 return sal_False; 1128 1129 ++rRow; // naechste Zelle ist gesucht 1130 1131 while ( rCol <= MAXCOL ) 1132 { 1133 const ScMarkArray& rArray = pMarkArray[rCol]; 1134 while ( rRow <= MAXROW ) 1135 { 1136 SCROW nStart = (SCROW) rArray.GetNextMarked( (SCsROW) rRow, sal_False ); 1137 if ( nStart <= MAXROW ) 1138 { 1139 SCROW nEnd = rArray.GetMarkEnd( nStart, sal_False ); 1140 ScColumnIterator aColIter( &aCol[rCol], nStart, nEnd ); 1141 SCROW nCellRow; 1142 ScBaseCell* pCell = NULL; 1143 while ( aColIter.Next( nCellRow, pCell ) ) 1144 { 1145 if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE ) 1146 { 1147 rRow = nCellRow; 1148 return sal_True; // Zelle gefunden 1149 } 1150 } 1151 rRow = nEnd + 1; // naechsten markierten Bereich suchen 1152 } 1153 else 1154 rRow = MAXROW + 1; // Ende der Spalte 1155 } 1156 rRow = 0; 1157 ++rCol; // naechste Spalte testen 1158 } 1159 1160 return sal_False; // alle Spalten durch 1161 } 1162 1163 void ScTable::UpdateDrawRef( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, 1164 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, 1165 SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bUpdateNoteCaptionPos ) 1166 { 1167 if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // only within the table 1168 { 1169 InitializeNoteCaptions(); 1170 ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer(); 1171 if ( eUpdateRefMode != URM_COPY && pDrawLayer ) 1172 { 1173 if ( eUpdateRefMode == URM_MOVE ) 1174 { // source range 1175 nCol1 = sal::static_int_cast<SCCOL>( nCol1 - nDx ); 1176 nRow1 = sal::static_int_cast<SCROW>( nRow1 - nDy ); 1177 nCol2 = sal::static_int_cast<SCCOL>( nCol2 - nDx ); 1178 nRow2 = sal::static_int_cast<SCROW>( nRow2 - nDy ); 1179 } 1180 pDrawLayer->MoveArea( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy, 1181 (eUpdateRefMode == URM_INSDEL), bUpdateNoteCaptionPos ); 1182 } 1183 } 1184 } 1185 1186 void ScTable::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, 1187 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz, 1188 ScDocument* pUndoDoc, sal_Bool bIncludeDraw, bool bUpdateNoteCaptionPos ) 1189 { 1190 SCCOL i; 1191 SCCOL iMax; 1192 if ( eUpdateRefMode == URM_COPY ) 1193 { 1194 i = nCol1; 1195 iMax = nCol2; 1196 } 1197 else 1198 { 1199 i = 0; 1200 iMax = MAXCOL; 1201 } 1202 for ( ; i<=iMax; i++) 1203 aCol[i].UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, 1204 nDx, nDy, nDz, pUndoDoc ); 1205 1206 if ( bIncludeDraw ) 1207 UpdateDrawRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, bUpdateNoteCaptionPos ); 1208 1209 if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // print ranges: only within the table 1210 { 1211 SCTAB nSTab = nTab; 1212 SCTAB nETab = nTab; 1213 SCCOL nSCol = 0; 1214 SCROW nSRow = 0; 1215 SCCOL nECol = 0; 1216 SCROW nERow = 0; 1217 sal_Bool bRecalcPages = sal_False; 1218 1219 for ( ScRangeVec::iterator aIt = aPrintRanges.begin(), aEnd = aPrintRanges.end(); aIt != aEnd; ++aIt ) 1220 { 1221 nSCol = aIt->aStart.Col(); 1222 nSRow = aIt->aStart.Row(); 1223 nECol = aIt->aEnd.Col(); 1224 nERow = aIt->aEnd.Row(); 1225 1226 // do not try to modify sheet index of print range 1227 if ( ScRefUpdate::Update( pDocument, eUpdateRefMode, 1228 nCol1,nRow1,nTab, nCol2,nRow2,nTab, 1229 nDx,nDy,0, 1230 nSCol,nSRow,nSTab, nECol,nERow,nETab ) ) 1231 { 1232 *aIt = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 ); 1233 bRecalcPages = sal_True; 1234 } 1235 } 1236 1237 if ( pRepeatColRange ) 1238 { 1239 nSCol = pRepeatColRange->aStart.Col(); 1240 nSRow = pRepeatColRange->aStart.Row(); 1241 nECol = pRepeatColRange->aEnd.Col(); 1242 nERow = pRepeatColRange->aEnd.Row(); 1243 1244 // do not try to modify sheet index of repeat range 1245 if ( ScRefUpdate::Update( pDocument, eUpdateRefMode, 1246 nCol1,nRow1,nTab, nCol2,nRow2,nTab, 1247 nDx,nDy,0, 1248 nSCol,nSRow,nSTab, nECol,nERow,nETab ) ) 1249 { 1250 *pRepeatColRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 ); 1251 bRecalcPages = sal_True; 1252 nRepeatStartX = nSCol; // fuer UpdatePageBreaks 1253 nRepeatEndX = nECol; 1254 } 1255 } 1256 1257 if ( pRepeatRowRange ) 1258 { 1259 nSCol = pRepeatRowRange->aStart.Col(); 1260 nSRow = pRepeatRowRange->aStart.Row(); 1261 nECol = pRepeatRowRange->aEnd.Col(); 1262 nERow = pRepeatRowRange->aEnd.Row(); 1263 1264 // do not try to modify sheet index of repeat range 1265 if ( ScRefUpdate::Update( pDocument, eUpdateRefMode, 1266 nCol1,nRow1,nTab, nCol2,nRow2,nTab, 1267 nDx,nDy,0, 1268 nSCol,nSRow,nSTab, nECol,nERow,nETab ) ) 1269 { 1270 *pRepeatRowRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 ); 1271 bRecalcPages = sal_True; 1272 nRepeatStartY = nSRow; // fuer UpdatePageBreaks 1273 nRepeatEndY = nERow; 1274 } 1275 } 1276 1277 // updating print ranges is not necessary with multiple print ranges 1278 if ( bRecalcPages && GetPrintRangeCount() <= 1 ) 1279 { 1280 UpdatePageBreaks(NULL); 1281 1282 pDocument->RepaintRange( ScRange(0,0,nTab,MAXCOL,MAXROW,nTab) ); 1283 } 1284 } 1285 } 1286 1287 void ScTable::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest, 1288 ScDocument* pUndoDoc ) 1289 { 1290 for ( SCCOL i=0; i<=MAXCOL; i++ ) 1291 aCol[i].UpdateTranspose( rSource, rDest, pUndoDoc ); 1292 } 1293 1294 void ScTable::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ) 1295 { 1296 for ( SCCOL i=0; i<=MAXCOL; i++ ) 1297 aCol[i].UpdateGrow( rArea, nGrowX, nGrowY ); 1298 } 1299 1300 void ScTable::UpdateInsertTab(SCTAB nTable) 1301 { 1302 if (nTab >= nTable) nTab++; 1303 for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTab(nTable); 1304 1305 if (IsStreamValid()) 1306 SetStreamValid(sal_False); 1307 } 1308 1309 //UNUSED2008-05 void ScTable::UpdateInsertTabOnlyCells(SCTAB nTable) 1310 //UNUSED2008-05 { 1311 //UNUSED2008-05 for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTabOnlyCells(nTable); 1312 //UNUSED2008-05 } 1313 1314 void ScTable::UpdateDeleteTab( SCTAB nTable, sal_Bool bIsMove, ScTable* pRefUndo ) 1315 { 1316 if (nTab > nTable) nTab--; 1317 1318 SCCOL i; 1319 if (pRefUndo) 1320 for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, &pRefUndo->aCol[i]); 1321 else 1322 for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, NULL); 1323 1324 if (IsStreamValid()) 1325 SetStreamValid(sal_False); 1326 } 1327 1328 void ScTable::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo, 1329 ScProgress& rProgress ) 1330 { 1331 nTab = nTabNo; 1332 for ( SCCOL i=0; i <= MAXCOL; i++ ) 1333 { 1334 aCol[i].UpdateMoveTab( nOldPos, nNewPos, nTabNo ); 1335 rProgress.SetState( rProgress.GetState() + aCol[i].GetCodeCount() ); 1336 } 1337 1338 if (IsStreamValid()) 1339 SetStreamValid(sal_False); 1340 } 1341 1342 void ScTable::UpdateCompile( sal_Bool bForceIfNameInUse ) 1343 { 1344 for (SCCOL i=0; i <= MAXCOL; i++) 1345 { 1346 aCol[i].UpdateCompile( bForceIfNameInUse ); 1347 } 1348 } 1349 1350 void ScTable::SetTabNo(SCTAB nNewTab) 1351 { 1352 nTab = nNewTab; 1353 for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].SetTabNo(nNewTab); 1354 } 1355 1356 sal_Bool ScTable::IsRangeNameInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, 1357 sal_uInt16 nIndex) const 1358 { 1359 sal_Bool bInUse = sal_False; 1360 for (SCCOL i = nCol1; !bInUse && (i <= nCol2) && (ValidCol(i)); i++) 1361 bInUse = aCol[i].IsRangeNameInUse(nRow1, nRow2, nIndex); 1362 return bInUse; 1363 } 1364 1365 void ScTable::FindRangeNamesInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, 1366 std::set<sal_uInt16>& rIndexes) const 1367 { 1368 for (SCCOL i = nCol1; i <= nCol2 && ValidCol(i); i++) 1369 aCol[i].FindRangeNamesInUse(nRow1, nRow2, rIndexes); 1370 } 1371 1372 void ScTable::ReplaceRangeNamesInUse(SCCOL nCol1, SCROW nRow1, 1373 SCCOL nCol2, SCROW nRow2, 1374 const ScRangeData::IndexMap& rMap ) 1375 { 1376 for (SCCOL i = nCol1; i <= nCol2 && (ValidCol(i)); i++) 1377 { 1378 aCol[i].ReplaceRangeNamesInUse( nRow1, nRow2, rMap ); 1379 } 1380 } 1381 1382 void ScTable::ExtendPrintArea( OutputDevice* pDev, 1383 SCCOL /* nStartCol */, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow ) 1384 { 1385 if ( !pColFlags || !pRowFlags ) 1386 { 1387 DBG_ERROR("keine ColInfo oder RowInfo in ExtendPrintArea"); 1388 return; 1389 } 1390 1391 Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP ); 1392 double nPPTX = aPix1000.X() / 1000.0; 1393 double nPPTY = aPix1000.Y() / 1000.0; 1394 1395 // First, mark those columns that we need to skip i.e. hidden and empty columns. 1396 1397 ScFlatBoolColSegments aSkipCols; 1398 aSkipCols.setInsertFromBack(true); // speed optimazation. 1399 aSkipCols.setFalse(0, MAXCOL); 1400 for (SCCOL i = 0; i <= MAXCOL; ++i) 1401 { 1402 SCCOL nLastCol = i; 1403 if (ColHidden(i, NULL, &nLastCol)) 1404 { 1405 // Columns are hidden in this range. 1406 aSkipCols.setTrue(i, nLastCol); 1407 } 1408 else 1409 { 1410 // These columns are visible. Check for empty columns. 1411 for (SCCOL j = i; j <= nLastCol; ++j) 1412 { 1413 if (aCol[j].GetCellCount() == 0) 1414 // empty 1415 aSkipCols.setTrue(j,j); 1416 } 1417 } 1418 i = nLastCol; 1419 } 1420 1421 ScFlatBoolColSegments::RangeData aColData; 1422 for (SCCOL nCol = rEndCol; nCol >= 0; --nCol) 1423 { 1424 if (!aSkipCols.getRangeData(nCol, aColData)) 1425 // Failed to get the data. This should never happen! 1426 return; 1427 1428 if (aColData.mbValue) 1429 { 1430 // Skip these columns. 1431 nCol = aColData.mnCol1; // move toward 0. 1432 continue; 1433 } 1434 1435 // These are visible and non-empty columns. 1436 for (SCCOL nDataCol = nCol; 0 <= nDataCol && nDataCol >= aColData.mnCol1; --nDataCol) 1437 { 1438 SCCOL nPrintCol = nDataCol; 1439 VisibleDataCellIterator aIter(*mpHiddenRows, aCol[nDataCol]); 1440 ScBaseCell* pCell = aIter.reset(nStartRow); 1441 if (!pCell) 1442 // No visible cells found in this column. Skip it. 1443 continue; 1444 1445 while (pCell) 1446 { 1447 SCCOL nNewCol = nDataCol; 1448 SCROW nRow = aIter.getRow(); 1449 if (nRow > nEndRow) 1450 // Went past the last row position. Bail out. 1451 break; 1452 1453 MaybeAddExtraColumn(nNewCol, nRow, pDev, nPPTX, nPPTY); 1454 if (nNewCol > nPrintCol) 1455 nPrintCol = nNewCol; 1456 pCell = aIter.next(); 1457 } 1458 1459 if (nPrintCol > rEndCol) 1460 // Make sure we don't shrink the print area. 1461 rEndCol = nPrintCol; 1462 } 1463 nCol = aColData.mnCol1; // move toward 0. 1464 } 1465 } 1466 1467 void ScTable::MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY) 1468 { 1469 ScBaseCell* pCell = aCol[rCol].GetCell(nRow); 1470 if (!pCell || !pCell->HasStringData()) 1471 return; 1472 1473 bool bFormula = false; //! ueberge 1474 long nPixel = pCell->GetTextWidth(); 1475 1476 // Breite bereits im Idle-Handler berechnet? 1477 if ( TEXTWIDTH_DIRTY == nPixel ) 1478 { 1479 ScNeededSizeOptions aOptions; 1480 aOptions.bTotalSize = sal_True; 1481 aOptions.bFormula = bFormula; 1482 aOptions.bSkipMerged = sal_False; 1483 1484 Fraction aZoom(1,1); 1485 nPixel = aCol[rCol].GetNeededSize( 1486 nRow, pDev, nPPTX, nPPTY, aZoom, aZoom, true, aOptions ); 1487 pCell->SetTextWidth( (sal_uInt16)nPixel ); 1488 } 1489 1490 long nTwips = (long) (nPixel / nPPTX); 1491 long nDocW = GetColWidth( rCol ); 1492 1493 long nMissing = nTwips - nDocW; 1494 if ( nMissing > 0 ) 1495 { 1496 // look at alignment 1497 1498 const ScPatternAttr* pPattern = GetPattern( rCol, nRow ); 1499 const SfxItemSet* pCondSet = NULL; 1500 if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() ) 1501 pCondSet = pDocument->GetCondResult( rCol, nRow, nTab ); 1502 1503 SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&) 1504 pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue(); 1505 if ( eHorJust == SVX_HOR_JUSTIFY_CENTER ) 1506 nMissing /= 2; // distributed into both directions 1507 else 1508 { 1509 // STANDARD is LEFT (only text is handled here) 1510 bool bRight = ( eHorJust == SVX_HOR_JUSTIFY_RIGHT ); 1511 if ( IsLayoutRTL() ) 1512 bRight = !bRight; 1513 if ( bRight ) 1514 nMissing = 0; // extended only to the left (logical) 1515 } 1516 } 1517 1518 SCCOL nNewCol = rCol; 1519 while (nMissing > 0 && nNewCol < MAXCOL) 1520 { 1521 ScBaseCell* pNextCell = aCol[nNewCol+1].GetCell(nRow); 1522 if (pNextCell && pNextCell->GetCellType() != CELLTYPE_NOTE) 1523 // Cell content in a next column ends display of this string. 1524 nMissing = 0; 1525 else 1526 nMissing -= GetColWidth(++nNewCol); 1527 } 1528 rCol = nNewCol; 1529 } 1530 1531 void ScTable::DoColResize( SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd ) 1532 { 1533 for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++) 1534 aCol[nCol].Resize(aCol[nCol].GetCellCount() + nAdd); 1535 } 1536 1537 #define SET_PRINTRANGE( p1, p2 ) \ 1538 if ( (p2) ) \ 1539 { \ 1540 if ( (p1) ) \ 1541 *(p1) = *(p2); \ 1542 else \ 1543 (p1) = new ScRange( *(p2) ); \ 1544 } \ 1545 else \ 1546 DELETEZ( (p1) ) 1547 1548 void ScTable::SetRepeatColRange( const ScRange* pNew ) 1549 { 1550 SET_PRINTRANGE( pRepeatColRange, pNew ); 1551 1552 if (IsStreamValid()) 1553 SetStreamValid(sal_False); 1554 } 1555 1556 void ScTable::SetRepeatRowRange( const ScRange* pNew ) 1557 { 1558 SET_PRINTRANGE( pRepeatRowRange, pNew ); 1559 1560 if (IsStreamValid()) 1561 SetStreamValid(sal_False); 1562 } 1563 1564 void ScTable::ClearPrintRanges() 1565 { 1566 aPrintRanges.clear(); 1567 bPrintEntireSheet = sal_False; 1568 InvalidatePageBreaks(); // #i117952# forget page breaks for an old print range 1569 1570 if (IsStreamValid()) 1571 SetStreamValid(sal_False); 1572 } 1573 1574 void ScTable::AddPrintRange( const ScRange& rNew ) 1575 { 1576 bPrintEntireSheet = sal_False; 1577 if( aPrintRanges.size() < 0xFFFF ) 1578 aPrintRanges.push_back( rNew ); 1579 1580 if (IsStreamValid()) 1581 SetStreamValid(sal_False); 1582 } 1583 1584 //UNUSED2009-05 void ScTable::SetPrintRange( const ScRange& rNew ) 1585 //UNUSED2009-05 { 1586 //UNUSED2009-05 ClearPrintRanges(); 1587 //UNUSED2009-05 AddPrintRange( rNew ); 1588 //UNUSED2009-05 } 1589 1590 void ScTable::SetPrintEntireSheet() 1591 { 1592 if( !IsPrintEntireSheet() ) 1593 { 1594 ClearPrintRanges(); 1595 bPrintEntireSheet = sal_True; 1596 } 1597 } 1598 1599 const ScRange* ScTable::GetPrintRange(sal_uInt16 nPos) const 1600 { 1601 return (nPos < GetPrintRangeCount()) ? &aPrintRanges[ nPos ] : NULL; 1602 } 1603 1604 void ScTable::FillPrintSaver( ScPrintSaverTab& rSaveTab ) const 1605 { 1606 rSaveTab.SetAreas( aPrintRanges, bPrintEntireSheet ); 1607 rSaveTab.SetRepeat( pRepeatColRange, pRepeatRowRange ); 1608 } 1609 1610 void ScTable::RestorePrintRanges( const ScPrintSaverTab& rSaveTab ) 1611 { 1612 aPrintRanges = rSaveTab.GetPrintRanges(); 1613 bPrintEntireSheet = rSaveTab.IsEntireSheet(); 1614 SetRepeatColRange( rSaveTab.GetRepeatCol() ); 1615 SetRepeatRowRange( rSaveTab.GetRepeatRow() ); 1616 1617 InvalidatePageBreaks(); // #i117952# forget page breaks for an old print range 1618 UpdatePageBreaks(NULL); 1619 } 1620 1621 SCROW ScTable::VisibleDataCellIterator::ROW_NOT_FOUND = -1; 1622 1623 ScTable::VisibleDataCellIterator::VisibleDataCellIterator(ScFlatBoolRowSegments& rRowSegs, ScColumn& rColumn) : 1624 mrRowSegs(rRowSegs), 1625 mrColumn(rColumn), 1626 mpCell(NULL), 1627 mnCurRow(ROW_NOT_FOUND), 1628 mnUBound(ROW_NOT_FOUND) 1629 { 1630 } 1631 1632 ScTable::VisibleDataCellIterator::~VisibleDataCellIterator() 1633 { 1634 } 1635 1636 ScBaseCell* ScTable::VisibleDataCellIterator::reset(SCROW nRow) 1637 { 1638 if (nRow > MAXROW) 1639 { 1640 mnCurRow = ROW_NOT_FOUND; 1641 return NULL; 1642 } 1643 1644 ScFlatBoolRowSegments::RangeData aData; 1645 if (!mrRowSegs.getRangeData(nRow, aData)) 1646 { 1647 mnCurRow = ROW_NOT_FOUND; 1648 return NULL; 1649 } 1650 1651 if (!aData.mbValue) 1652 { 1653 // specified row is visible. Take it. 1654 mnCurRow = nRow; 1655 mnUBound = aData.mnRow2; 1656 } 1657 else 1658 { 1659 // specified row is not-visible. The first visible row is the start of 1660 // the next segment. 1661 mnCurRow = aData.mnRow2 + 1; 1662 mnUBound = mnCurRow; // get range data on the next iteration. 1663 if (mnCurRow > MAXROW) 1664 { 1665 // Make sure the row doesn't exceed our current limit. 1666 mnCurRow = ROW_NOT_FOUND; 1667 return NULL; 1668 } 1669 } 1670 1671 mpCell = mrColumn.GetCell(mnCurRow); 1672 if (mpCell) 1673 // First visible cell found. 1674 return mpCell; 1675 1676 // Find a first visible cell below this row (if any). 1677 return next(); 1678 } 1679 1680 ScBaseCell* ScTable::VisibleDataCellIterator::next() 1681 { 1682 if (mnCurRow == ROW_NOT_FOUND) 1683 return NULL; 1684 1685 while (mrColumn.GetNextDataPos(mnCurRow)) 1686 { 1687 if (mnCurRow > mnUBound) 1688 { 1689 // We don't know the visibility of this row range. Query it. 1690 ScFlatBoolRowSegments::RangeData aData; 1691 if (!mrRowSegs.getRangeData(mnCurRow, aData)) 1692 { 1693 mnCurRow = ROW_NOT_FOUND; 1694 return NULL; 1695 } 1696 1697 if (aData.mbValue) 1698 { 1699 // This row is invisible. Skip to the last invisible row and 1700 // try again. 1701 mnCurRow = mnUBound = aData.mnRow2; 1702 continue; 1703 } 1704 1705 // This row is visible. 1706 mnUBound = aData.mnRow2; 1707 } 1708 1709 mpCell = mrColumn.GetCell(mnCurRow); 1710 if (mpCell) 1711 return mpCell; 1712 } 1713 mnCurRow = ROW_NOT_FOUND; 1714 return NULL; 1715 } 1716 1717 SCROW ScTable::VisibleDataCellIterator::getRow() const 1718 { 1719 return mnCurRow; 1720 } 1721 1722