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