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 void ScTable::GetLastAttrCell( SCCOL& rEndCol, SCROW& rEndRow ) const 436 { 437 SCCOL nMaxX = 0; 438 SCROW nMaxY = 0; 439 SCCOL i; 440 for ( i = 0; i <= MAXCOL; i++ ) 441 { 442 SCROW nLastRow; 443 aCol[i].GetLastAttr( nLastRow ); 444 if ( nLastRow > nMaxY && nLastRow > 0 && nLastRow <= MAXROW ) 445 { 446 nMaxY = nLastRow; 447 nMaxX = i; 448 } 449 } 450 rEndCol = nMaxX; 451 rEndRow = nMaxY; 452 } 453 /* vorher: 454 455 sal_Bool bFound = sal_False; 456 SCCOL nMaxX = 0; 457 SCROW nMaxY = 0; 458 for (SCCOL i=0; i<=MAXCOL; i++) 459 if (!aCol[i].IsEmpty()) 460 { 461 bFound = sal_True; 462 nMaxX = i; 463 SCCOL nColY = aCol[i].GetLastEntryPos(); 464 if (nColY > nMaxY) 465 nMaxY = nColY; 466 } 467 468 rEndCol = nMaxX; 469 rEndRow = nMaxY; 470 return bFound; 471 */ 472 473 const SCCOL SC_COLUMNS_STOP = 30; 474 475 sal_Bool ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, sal_Bool bNotes ) const 476 { 477 sal_Bool bFound = sal_False; 478 SCCOL nMaxX = 0; 479 SCROW nMaxY = 0; 480 SCCOL i; 481 482 for (i=0; i<=MAXCOL; i++) // Daten testen 483 if (!aCol[i].IsEmptyVisData(bNotes)) 484 { 485 bFound = sal_True; 486 if (i>nMaxX) 487 nMaxX = i; 488 SCROW nColY = aCol[i].GetLastVisDataPos(bNotes); 489 if (nColY > nMaxY) 490 nMaxY = nColY; 491 } 492 493 SCCOL nMaxDataX = nMaxX; 494 495 for (i=0; i<=MAXCOL; i++) // Attribute testen 496 { 497 SCROW nLastRow; 498 if (aCol[i].GetLastVisibleAttr( nLastRow )) 499 { 500 bFound = sal_True; 501 nMaxX = i; 502 if (nLastRow > nMaxY) 503 nMaxY = nLastRow; 504 } 505 } 506 507 if (nMaxX == MAXCOL) // Attribute rechts weglassen 508 { 509 --nMaxX; 510 while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1]) ) 511 --nMaxX; 512 } 513 514 if ( nMaxX < nMaxDataX ) 515 { 516 nMaxX = nMaxDataX; 517 } 518 else if ( nMaxX > nMaxDataX ) 519 { 520 SCCOL nAttrStartX = nMaxDataX + 1; 521 while ( nAttrStartX < MAXCOL ) 522 { 523 SCCOL nAttrEndX = nAttrStartX; 524 while ( nAttrEndX < MAXCOL && aCol[nAttrStartX].IsVisibleAttrEqual(aCol[nAttrEndX+1]) ) 525 ++nAttrEndX; 526 if ( nAttrEndX + 1 - nAttrStartX >= SC_COLUMNS_STOP ) 527 { 528 // found equally-formatted columns behind data -> stop before these columns 529 nMaxX = nAttrStartX - 1; 530 531 // also don't include default-formatted columns before that 532 SCROW nDummyRow; 533 while ( nMaxX > nMaxDataX && !aCol[nMaxX].GetLastVisibleAttr( nDummyRow ) ) 534 --nMaxX; 535 break; 536 } 537 nAttrStartX = nAttrEndX + 1; 538 } 539 } 540 541 rEndCol = nMaxX; 542 rEndRow = nMaxY; 543 return bFound; 544 } 545 546 sal_Bool ScTable::GetPrintAreaHor( SCROW nStartRow, SCROW nEndRow, 547 SCCOL& rEndCol, sal_Bool /* bNotes */ ) const 548 { 549 sal_Bool bFound = sal_False; 550 SCCOL nMaxX = 0; 551 SCCOL i; 552 553 for (i=0; i<=MAXCOL; i++) // Attribute testen 554 { 555 if (aCol[i].HasVisibleAttrIn( nStartRow, nEndRow )) 556 { 557 bFound = sal_True; 558 nMaxX = i; 559 } 560 } 561 562 if (nMaxX == MAXCOL) // Attribute rechts weglassen 563 { 564 --nMaxX; 565 while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1], nStartRow, nEndRow) ) 566 --nMaxX; 567 } 568 569 for (i=0; i<=MAXCOL; i++) // Daten testen 570 { 571 if (!aCol[i].IsEmptyBlock( nStartRow, nEndRow )) //! bNotes ?????? 572 { 573 bFound = sal_True; 574 if (i>nMaxX) 575 nMaxX = i; 576 } 577 } 578 579 rEndCol = nMaxX; 580 return bFound; 581 } 582 583 sal_Bool ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol, 584 SCROW& rEndRow, sal_Bool bNotes ) const 585 { 586 sal_Bool bFound = sal_False; 587 SCROW nMaxY = 0; 588 SCCOL i; 589 590 for (i=nStartCol; i<=nEndCol; i++) // Attribute testen 591 { 592 SCROW nLastRow; 593 if (aCol[i].GetLastVisibleAttr( nLastRow )) 594 { 595 bFound = sal_True; 596 if (nLastRow > nMaxY) 597 nMaxY = nLastRow; 598 } 599 } 600 601 for (i=nStartCol; i<=nEndCol; i++) // Daten testen 602 if (!aCol[i].IsEmptyVisData(bNotes)) 603 { 604 bFound = sal_True; 605 SCROW nColY = aCol[i].GetLastVisDataPos(bNotes); 606 if (nColY > nMaxY) 607 nMaxY = nColY; 608 } 609 610 rEndRow = nMaxY; 611 return bFound; 612 } 613 614 sal_Bool ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const 615 { 616 sal_Bool bFound = sal_False; 617 SCCOL nMinX = MAXCOL; 618 SCROW nMinY = MAXROW; 619 SCCOL i; 620 621 for (i=0; i<=MAXCOL; i++) // Attribute testen 622 { 623 SCROW nFirstRow; 624 if (aCol[i].GetFirstVisibleAttr( nFirstRow )) 625 { 626 if (!bFound) 627 nMinX = i; 628 bFound = sal_True; 629 if (nFirstRow < nMinY) 630 nMinY = nFirstRow; 631 } 632 } 633 634 if (nMinX == 0) // Attribute links weglassen 635 { 636 if ( aCol[0].IsVisibleAttrEqual(aCol[1]) ) // keine einzelnen 637 { 638 ++nMinX; 639 while ( nMinX<MAXCOL && aCol[nMinX].IsVisibleAttrEqual(aCol[nMinX-1]) ) 640 ++nMinX; 641 } 642 } 643 644 sal_Bool bDatFound = sal_False; 645 for (i=0; i<=MAXCOL; i++) // Daten testen 646 if (!aCol[i].IsEmptyVisData(sal_True)) 647 { 648 if (!bDatFound && i<nMinX) 649 nMinX = i; 650 bFound = bDatFound = sal_True; 651 SCROW nColY = aCol[i].GetFirstVisDataPos(sal_True); 652 if (nColY < nMinY) 653 nMinY = nColY; 654 } 655 656 rStartCol = nMinX; 657 rStartRow = nMinY; 658 return bFound; 659 } 660 661 void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow, 662 sal_Bool bIncludeOld, bool bOnlyDown ) const 663 { 664 sal_Bool bLeft = sal_False; 665 sal_Bool bRight = sal_False; 666 sal_Bool bTop = sal_False; 667 sal_Bool bBottom = sal_False; 668 sal_Bool bChanged; 669 sal_Bool bFound; 670 SCCOL i; 671 SCROW nTest; 672 673 do 674 { 675 bChanged = sal_False; 676 677 if (!bOnlyDown) 678 { 679 SCROW nStart = rStartRow; 680 SCROW nEnd = rEndRow; 681 if (nStart>0) --nStart; 682 if (nEnd<MAXROW) ++nEnd; 683 684 if (rEndCol < MAXCOL) 685 if (!aCol[rEndCol+1].IsEmptyBlock(nStart,nEnd)) 686 { 687 ++rEndCol; 688 bChanged = sal_True; 689 bRight = sal_True; 690 } 691 692 if (rStartCol > 0) 693 if (!aCol[rStartCol-1].IsEmptyBlock(nStart,nEnd)) 694 { 695 --rStartCol; 696 bChanged = sal_True; 697 bLeft = sal_True; 698 } 699 700 if (rStartRow > 0) 701 { 702 nTest = rStartRow-1; 703 bFound = sal_False; 704 for (i=rStartCol; i<=rEndCol && !bFound; i++) 705 if (aCol[i].HasDataAt(nTest)) 706 bFound = sal_True; 707 if (bFound) 708 { 709 --rStartRow; 710 bChanged = sal_True; 711 bTop = sal_True; 712 } 713 } 714 } 715 716 if (rEndRow < MAXROW) 717 { 718 nTest = rEndRow+1; 719 bFound = sal_False; 720 for (i=rStartCol; i<=rEndCol && !bFound; i++) 721 if (aCol[i].HasDataAt(nTest)) 722 bFound = sal_True; 723 if (bFound) 724 { 725 ++rEndRow; 726 bChanged = sal_True; 727 bBottom = sal_True; 728 } 729 } 730 } 731 while( bChanged ); 732 733 if ( !bIncludeOld ) 734 { 735 if ( !bLeft && rStartCol < MAXCOL && rStartCol < rEndCol ) 736 if ( aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) ) 737 ++rStartCol; 738 if ( !bRight && rEndCol > 0 && rStartCol < rEndCol ) 739 if ( aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) ) 740 --rEndCol; 741 if ( !bTop && rStartRow < MAXROW && rStartRow < rEndRow ) 742 { 743 bFound = sal_False; 744 for (i=rStartCol; i<=rEndCol && !bFound; i++) 745 if (aCol[i].HasDataAt(rStartRow)) 746 bFound = sal_True; 747 if (!bFound) 748 ++rStartRow; 749 } 750 if ( !bBottom && rEndRow > 0 && rStartRow < rEndRow ) 751 { 752 bFound = sal_False; 753 for (i=rStartCol; i<=rEndCol && !bFound; i++) 754 if (aCol[i].HasDataAt(rEndRow)) 755 bFound = sal_True; 756 if (!bFound) 757 --rEndRow; 758 } 759 } 760 } 761 762 763 bool ScTable::ShrinkToUsedDataArea( bool& o_bShrunk, SCCOL& rStartCol, SCROW& rStartRow, 764 SCCOL& rEndCol, SCROW& rEndRow, bool bColumnsOnly ) const 765 { 766 o_bShrunk = false; 767 768 PutInOrder( rStartCol, rEndCol); 769 PutInOrder( rStartRow, rEndRow); 770 if (rStartCol < 0) 771 rStartCol = 0, o_bShrunk = true; 772 if (rStartRow < 0) 773 rStartRow = 0, o_bShrunk = true; 774 if (rEndCol > MAXCOL) 775 rEndCol = MAXCOL, o_bShrunk = true; 776 if (rEndRow > MAXROW) 777 rEndRow = MAXROW, o_bShrunk = true; 778 779 bool bChanged; 780 do 781 { 782 bChanged = false; 783 784 while (rStartCol < rEndCol) 785 { 786 if (aCol[rEndCol].IsEmptyBlock( rStartRow, rEndRow)) 787 { 788 --rEndCol; 789 bChanged = true; 790 } 791 else 792 break; // while 793 } 794 795 while (rStartCol < rEndCol) 796 { 797 if (aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow)) 798 { 799 ++rStartCol; 800 bChanged = true; 801 } 802 else 803 break; // while 804 } 805 806 if (!bColumnsOnly) 807 { 808 if (rStartRow < rEndRow) 809 { 810 bool bFound = false; 811 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++) 812 if (aCol[i].HasDataAt( rStartRow)) 813 bFound = true; 814 if (!bFound) 815 { 816 ++rStartRow; 817 bChanged = true; 818 } 819 } 820 821 if (rStartRow < rEndRow) 822 { 823 bool bFound = false; 824 for (SCCOL i=rStartCol; i<=rEndCol && !bFound; i++) 825 if (aCol[i].HasDataAt( rEndRow)) 826 bFound = true; 827 if (!bFound) 828 { 829 --rEndRow; 830 bChanged = true; 831 } 832 } 833 } 834 835 if (bChanged) 836 o_bShrunk = true; 837 } while( bChanged ); 838 839 return rStartCol != rEndCol || (bColumnsOnly ? 840 !aCol[rStartCol].IsEmptyBlock( rStartRow, rEndRow) : 841 (rStartRow != rEndRow || aCol[rStartCol].HasDataAt( rStartRow))); 842 } 843 844 845 SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, 846 SCCOL nEndCol, SCROW nEndRow, ScDirection eDir ) 847 { 848 SCSIZE nCount = 0; 849 SCCOL nCol; 850 if ((eDir == DIR_BOTTOM) || (eDir == DIR_TOP)) 851 { 852 nCount = static_cast<SCSIZE>(nEndRow - nStartRow); 853 for (nCol = nStartCol; nCol <= nEndCol; nCol++) 854 nCount = Min(nCount, aCol[nCol].GetEmptyLinesInBlock(nStartRow, nEndRow, eDir)); 855 } 856 else if (eDir == DIR_RIGHT) 857 { 858 nCol = nEndCol; 859 while (((SCsCOL)nCol >= (SCsCOL)nStartCol) && 860 aCol[nCol].IsEmptyBlock(nStartRow, nEndRow)) 861 { 862 nCount++; 863 nCol--; 864 } 865 } 866 else 867 { 868 nCol = nStartCol; 869 while ((nCol <= nEndCol) && aCol[nCol].IsEmptyBlock(nStartRow, nEndRow)) 870 { 871 nCount++; 872 nCol++; 873 } 874 } 875 return nCount; 876 } 877 878 sal_Bool ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, SCCOL nEndCol ) 879 { 880 sal_Bool bFound = sal_False; 881 for (SCCOL i=nStartCol; i<=nEndCol && !bFound; i++) 882 if (aCol[i].HasDataAt(nRow)) 883 bFound = sal_True; 884 return !bFound; 885 } 886 887 void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow ) 888 { 889 while ( rStartCol<rEndCol && aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) ) 890 ++rStartCol; 891 892 while ( rStartCol<rEndCol && aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) ) 893 --rEndCol; 894 895 while ( rStartRow<rEndRow && IsEmptyLine(rStartRow, rStartCol, rEndCol) ) 896 ++rStartRow; 897 898 while ( rStartRow<rEndRow && IsEmptyLine(rEndRow, rStartCol, rEndCol) ) 899 --rEndRow; 900 } 901 902 void ScTable::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY ) 903 { 904 if (nMovX) 905 { 906 SCsCOL nNewCol = (SCsCOL) rCol; 907 sal_Bool bThere = aCol[nNewCol].HasVisibleDataAt(rRow); 908 sal_Bool bFnd; 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_False; 915 } 916 while (bFnd); 917 nNewCol = sal::static_int_cast<SCsCOL>( nNewCol - nMovX ); 918 919 if (nNewCol == (SCsCOL)rCol) 920 bThere = sal_False; 921 } 922 923 if (!bThere) 924 { 925 do 926 { 927 nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX ); 928 bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : sal_True; 929 } 930 while (!bFnd); 931 } 932 933 if (nNewCol<0) nNewCol=0; 934 if (nNewCol>MAXCOL) nNewCol=MAXCOL; 935 rCol = (SCCOL) nNewCol; 936 } 937 938 if (nMovY) 939 aCol[rCol].FindDataAreaPos(rRow,nMovY); 940 } 941 942 sal_Bool ScTable::ValidNextPos( SCCOL nCol, SCROW nRow, const ScMarkData& rMark, 943 sal_Bool bMarked, sal_Bool bUnprotected ) 944 { 945 if (!ValidCol(nCol) || !ValidRow(nRow)) 946 return sal_False; 947 948 if (pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) 949 // Skip an overlapped cell. 950 return false; 951 952 if (bMarked && !rMark.IsCellMarked(nCol,nRow)) 953 return sal_False; 954 955 if (bUnprotected && ((const ScProtectionAttr*) 956 GetAttr(nCol,nRow,ATTR_PROTECTION))->GetProtection()) 957 return sal_False; 958 959 if (bMarked || bUnprotected) //! auch sonst ??? 960 { 961 // #53697# ausgeblendete muessen uebersprungen werden, weil der Cursor sonst 962 // auf der naechsten Zelle landet, auch wenn die geschuetzt/nicht markiert ist. 963 //! per Extra-Parameter steuern, nur fuer Cursor-Bewegung ??? 964 965 if (RowHidden(nRow)) 966 return sal_False; 967 968 if (ColHidden(nCol)) 969 return sal_False; 970 } 971 972 return sal_True; 973 } 974 975 void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY, 976 sal_Bool bMarked, sal_Bool bUnprotected, const ScMarkData& rMark ) 977 { 978 if (bUnprotected && !IsProtected()) // Tabelle ueberhaupt geschuetzt? 979 bUnprotected = sal_False; 980 981 sal_uInt16 nWrap = 0; 982 SCsCOL nCol = rCol; 983 SCsROW nRow = rRow; 984 985 nCol = sal::static_int_cast<SCsCOL>( nCol + nMovX ); 986 nRow = sal::static_int_cast<SCsROW>( nRow + nMovY ); 987 988 DBG_ASSERT( !nMovY || !bUnprotected, 989 "GetNextPos mit bUnprotected horizontal nicht implementiert" ); 990 991 if ( nMovY && bMarked ) 992 { 993 sal_Bool bUp = ( nMovY < 0 ); 994 nRow = rMark.GetNextMarked( nCol, nRow, bUp ); 995 while ( VALIDROW(nRow) && 996 (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) ) 997 { 998 // #53697# ausgeblendete ueberspringen (s.o.) 999 nRow += nMovY; 1000 nRow = rMark.GetNextMarked( nCol, nRow, bUp ); 1001 } 1002 1003 while ( nRow < 0 || nRow > MAXROW ) 1004 { 1005 nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) ); 1006 while ( VALIDCOL(nCol) && ColHidden(nCol) ) 1007 nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) ); // #53697# skip hidden rows (see above) 1008 if (nCol < 0) 1009 { 1010 nCol = MAXCOL; 1011 if (++nWrap >= 2) 1012 return; 1013 } 1014 else if (nCol > MAXCOL) 1015 { 1016 nCol = 0; 1017 if (++nWrap >= 2) 1018 return; 1019 } 1020 if (nRow < 0) 1021 nRow = MAXROW; 1022 else if (nRow > MAXROW) 1023 nRow = 0; 1024 nRow = rMark.GetNextMarked( nCol, nRow, bUp ); 1025 while ( VALIDROW(nRow) && 1026 (RowHidden(nRow) || pDocument->HasAttrib(nCol, nRow, nTab, nCol, nRow, nTab, HASATTR_OVERLAPPED)) ) 1027 { 1028 // #53697# ausgeblendete ueberspringen (s.o.) 1029 nRow += nMovY; 1030 nRow = rMark.GetNextMarked( nCol, nRow, bUp ); 1031 } 1032 } 1033 } 1034 1035 if ( nMovX && ( bMarked || bUnprotected ) ) 1036 { 1037 // initiales Weiterzaehlen wrappen: 1038 if (nCol<0) 1039 { 1040 nCol = MAXCOL; 1041 --nRow; 1042 if (nRow<0) 1043 nRow = MAXROW; 1044 } 1045 if (nCol>MAXCOL) 1046 { 1047 nCol = 0; 1048 ++nRow; 1049 if (nRow>MAXROW) 1050 nRow = 0; 1051 } 1052 1053 if ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) ) 1054 { 1055 SCsROW* pNextRows = new SCsROW[MAXCOL+1]; 1056 SCCOL i; 1057 1058 if ( nMovX > 0 ) // vorwaerts 1059 { 1060 for (i=0; i<=MAXCOL; i++) 1061 pNextRows[i] = (i<nCol) ? (nRow+1) : nRow; 1062 do 1063 { 1064 SCsROW nNextRow = pNextRows[nCol] + 1; 1065 if ( bMarked ) 1066 nNextRow = rMark.GetNextMarked( nCol, nNextRow, sal_False ); 1067 if ( bUnprotected ) 1068 nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_False ); 1069 pNextRows[nCol] = nNextRow; 1070 1071 SCsROW nMinRow = MAXROW+1; 1072 for (i=0; i<=MAXCOL; i++) 1073 if (pNextRows[i] < nMinRow) // bei gleichen den linken 1074 { 1075 nMinRow = pNextRows[i]; 1076 nCol = i; 1077 } 1078 nRow = nMinRow; 1079 1080 if ( nRow > MAXROW ) 1081 { 1082 if (++nWrap >= 2) break; // ungueltigen Wert behalten 1083 nCol = 0; 1084 nRow = 0; 1085 for (i=0; i<=MAXCOL; i++) 1086 pNextRows[i] = 0; // alles ganz von vorne 1087 } 1088 } 1089 while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) ); 1090 } 1091 else // rueckwaerts 1092 { 1093 for (i=0; i<=MAXCOL; i++) 1094 pNextRows[i] = (i>nCol) ? (nRow-1) : nRow; 1095 do 1096 { 1097 SCsROW nNextRow = pNextRows[nCol] - 1; 1098 if ( bMarked ) 1099 nNextRow = rMark.GetNextMarked( nCol, nNextRow, sal_True ); 1100 if ( bUnprotected ) 1101 nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, sal_True ); 1102 pNextRows[nCol] = nNextRow; 1103 1104 SCsROW nMaxRow = -1; 1105 for (i=0; i<=MAXCOL; i++) 1106 if (pNextRows[i] >= nMaxRow) // bei gleichen den rechten 1107 { 1108 nMaxRow = pNextRows[i]; 1109 nCol = i; 1110 } 1111 nRow = nMaxRow; 1112 1113 if ( nRow < 0 ) 1114 { 1115 if (++nWrap >= 2) break; // ungueltigen Wert behalten 1116 nCol = MAXCOL; 1117 nRow = MAXROW; 1118 for (i=0; i<=MAXCOL; i++) 1119 pNextRows[i] = MAXROW; // alles ganz von vorne 1120 } 1121 } 1122 while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) ); 1123 } 1124 1125 delete[] pNextRows; 1126 } 1127 } 1128 1129 // ungueltige Werte kommen z.b. bei Tab heraus, 1130 // wenn nicht markiert und nicht geschuetzt ist (linker / rechter Rand), 1131 // dann Werte unveraendert lassen 1132 1133 if (VALIDCOLROW(nCol,nRow)) 1134 { 1135 rCol = nCol; 1136 rRow = nRow; 1137 } 1138 } 1139 1140 sal_Bool ScTable::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark ) 1141 { 1142 const ScMarkArray* pMarkArray = rMark.GetArray(); 1143 DBG_ASSERT(pMarkArray,"GetNextMarkedCell ohne MarkArray"); 1144 if ( !pMarkArray ) 1145 return sal_False; 1146 1147 ++rRow; // naechste Zelle ist gesucht 1148 1149 while ( rCol <= MAXCOL ) 1150 { 1151 const ScMarkArray& rArray = pMarkArray[rCol]; 1152 while ( rRow <= MAXROW ) 1153 { 1154 SCROW nStart = (SCROW) rArray.GetNextMarked( (SCsROW) rRow, sal_False ); 1155 if ( nStart <= MAXROW ) 1156 { 1157 SCROW nEnd = rArray.GetMarkEnd( nStart, sal_False ); 1158 ScColumnIterator aColIter( &aCol[rCol], nStart, nEnd ); 1159 SCROW nCellRow; 1160 ScBaseCell* pCell = NULL; 1161 while ( aColIter.Next( nCellRow, pCell ) ) 1162 { 1163 if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE ) 1164 { 1165 rRow = nCellRow; 1166 return sal_True; // Zelle gefunden 1167 } 1168 } 1169 rRow = nEnd + 1; // naechsten markierten Bereich suchen 1170 } 1171 else 1172 rRow = MAXROW + 1; // Ende der Spalte 1173 } 1174 rRow = 0; 1175 ++rCol; // naechste Spalte testen 1176 } 1177 1178 return sal_False; // alle Spalten durch 1179 } 1180 1181 void ScTable::UpdateDrawRef( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, 1182 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, 1183 SCsCOL nDx, SCsROW nDy, SCsTAB nDz, bool bUpdateNoteCaptionPos ) 1184 { 1185 if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // only within the table 1186 { 1187 InitializeNoteCaptions(); 1188 ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer(); 1189 if ( eUpdateRefMode != URM_COPY && pDrawLayer ) 1190 { 1191 if ( eUpdateRefMode == URM_MOVE ) 1192 { // source range 1193 nCol1 = sal::static_int_cast<SCCOL>( nCol1 - nDx ); 1194 nRow1 = sal::static_int_cast<SCROW>( nRow1 - nDy ); 1195 nCol2 = sal::static_int_cast<SCCOL>( nCol2 - nDx ); 1196 nRow2 = sal::static_int_cast<SCROW>( nRow2 - nDy ); 1197 } 1198 pDrawLayer->MoveArea( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy, 1199 (eUpdateRefMode == URM_INSDEL), bUpdateNoteCaptionPos ); 1200 } 1201 } 1202 } 1203 1204 void ScTable::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, 1205 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz, 1206 ScDocument* pUndoDoc, sal_Bool bIncludeDraw, bool bUpdateNoteCaptionPos ) 1207 { 1208 SCCOL i; 1209 SCCOL iMax; 1210 if ( eUpdateRefMode == URM_COPY ) 1211 { 1212 i = nCol1; 1213 iMax = nCol2; 1214 } 1215 else 1216 { 1217 i = 0; 1218 iMax = MAXCOL; 1219 } 1220 for ( ; i<=iMax; i++) 1221 aCol[i].UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, 1222 nDx, nDy, nDz, pUndoDoc ); 1223 1224 if ( bIncludeDraw ) 1225 UpdateDrawRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz, bUpdateNoteCaptionPos ); 1226 1227 if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // print ranges: only within the table 1228 { 1229 SCTAB nSTab = nTab; 1230 SCTAB nETab = nTab; 1231 SCCOL nSCol = 0; 1232 SCROW nSRow = 0; 1233 SCCOL nECol = 0; 1234 SCROW nERow = 0; 1235 sal_Bool bRecalcPages = sal_False; 1236 1237 for ( ScRangeVec::iterator aIt = aPrintRanges.begin(), aEnd = aPrintRanges.end(); aIt != aEnd; ++aIt ) 1238 { 1239 nSCol = aIt->aStart.Col(); 1240 nSRow = aIt->aStart.Row(); 1241 nECol = aIt->aEnd.Col(); 1242 nERow = aIt->aEnd.Row(); 1243 1244 // do not try to modify sheet index of print 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 *aIt = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 ); 1251 bRecalcPages = sal_True; 1252 } 1253 } 1254 1255 if ( pRepeatColRange ) 1256 { 1257 nSCol = pRepeatColRange->aStart.Col(); 1258 nSRow = pRepeatColRange->aStart.Row(); 1259 nECol = pRepeatColRange->aEnd.Col(); 1260 nERow = pRepeatColRange->aEnd.Row(); 1261 1262 // do not try to modify sheet index of repeat range 1263 if ( ScRefUpdate::Update( pDocument, eUpdateRefMode, 1264 nCol1,nRow1,nTab, nCol2,nRow2,nTab, 1265 nDx,nDy,0, 1266 nSCol,nSRow,nSTab, nECol,nERow,nETab ) ) 1267 { 1268 *pRepeatColRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 ); 1269 bRecalcPages = sal_True; 1270 nRepeatStartX = nSCol; // fuer UpdatePageBreaks 1271 nRepeatEndX = nECol; 1272 } 1273 } 1274 1275 if ( pRepeatRowRange ) 1276 { 1277 nSCol = pRepeatRowRange->aStart.Col(); 1278 nSRow = pRepeatRowRange->aStart.Row(); 1279 nECol = pRepeatRowRange->aEnd.Col(); 1280 nERow = pRepeatRowRange->aEnd.Row(); 1281 1282 // do not try to modify sheet index of repeat range 1283 if ( ScRefUpdate::Update( pDocument, eUpdateRefMode, 1284 nCol1,nRow1,nTab, nCol2,nRow2,nTab, 1285 nDx,nDy,0, 1286 nSCol,nSRow,nSTab, nECol,nERow,nETab ) ) 1287 { 1288 *pRepeatRowRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 ); 1289 bRecalcPages = sal_True; 1290 nRepeatStartY = nSRow; // fuer UpdatePageBreaks 1291 nRepeatEndY = nERow; 1292 } 1293 } 1294 1295 // updating print ranges is not necessary with multiple print ranges 1296 if ( bRecalcPages && GetPrintRangeCount() <= 1 ) 1297 { 1298 UpdatePageBreaks(NULL); 1299 1300 pDocument->RepaintRange( ScRange(0,0,nTab,MAXCOL,MAXROW,nTab) ); 1301 } 1302 } 1303 } 1304 1305 void ScTable::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest, 1306 ScDocument* pUndoDoc ) 1307 { 1308 for ( SCCOL i=0; i<=MAXCOL; i++ ) 1309 aCol[i].UpdateTranspose( rSource, rDest, pUndoDoc ); 1310 } 1311 1312 void ScTable::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ) 1313 { 1314 for ( SCCOL i=0; i<=MAXCOL; i++ ) 1315 aCol[i].UpdateGrow( rArea, nGrowX, nGrowY ); 1316 } 1317 1318 void ScTable::UpdateInsertTab(SCTAB nTable) 1319 { 1320 if (nTab >= nTable) nTab++; 1321 for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTab(nTable); 1322 1323 if (IsStreamValid()) 1324 SetStreamValid(sal_False); 1325 } 1326 1327 //UNUSED2008-05 void ScTable::UpdateInsertTabOnlyCells(SCTAB nTable) 1328 //UNUSED2008-05 { 1329 //UNUSED2008-05 for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTabOnlyCells(nTable); 1330 //UNUSED2008-05 } 1331 1332 void ScTable::UpdateDeleteTab( SCTAB nTable, sal_Bool bIsMove, ScTable* pRefUndo ) 1333 { 1334 if (nTab > nTable) nTab--; 1335 1336 SCCOL i; 1337 if (pRefUndo) 1338 for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, &pRefUndo->aCol[i]); 1339 else 1340 for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, NULL); 1341 1342 if (IsStreamValid()) 1343 SetStreamValid(sal_False); 1344 } 1345 1346 void ScTable::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo, 1347 ScProgress& rProgress ) 1348 { 1349 nTab = nTabNo; 1350 for ( SCCOL i=0; i <= MAXCOL; i++ ) 1351 { 1352 aCol[i].UpdateMoveTab( nOldPos, nNewPos, nTabNo ); 1353 rProgress.SetState( rProgress.GetState() + aCol[i].GetCodeCount() ); 1354 } 1355 1356 if (IsStreamValid()) 1357 SetStreamValid(sal_False); 1358 } 1359 1360 void ScTable::UpdateCompile( sal_Bool bForceIfNameInUse ) 1361 { 1362 for (SCCOL i=0; i <= MAXCOL; i++) 1363 { 1364 aCol[i].UpdateCompile( bForceIfNameInUse ); 1365 } 1366 } 1367 1368 void ScTable::SetTabNo(SCTAB nNewTab) 1369 { 1370 nTab = nNewTab; 1371 for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].SetTabNo(nNewTab); 1372 } 1373 1374 sal_Bool ScTable::IsRangeNameInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, 1375 sal_uInt16 nIndex) const 1376 { 1377 sal_Bool bInUse = sal_False; 1378 for (SCCOL i = nCol1; !bInUse && (i <= nCol2) && (ValidCol(i)); i++) 1379 bInUse = aCol[i].IsRangeNameInUse(nRow1, nRow2, nIndex); 1380 return bInUse; 1381 } 1382 1383 void ScTable::FindRangeNamesInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, 1384 std::set<sal_uInt16>& rIndexes) const 1385 { 1386 for (SCCOL i = nCol1; i <= nCol2 && ValidCol(i); i++) 1387 aCol[i].FindRangeNamesInUse(nRow1, nRow2, rIndexes); 1388 } 1389 1390 void ScTable::ReplaceRangeNamesInUse(SCCOL nCol1, SCROW nRow1, 1391 SCCOL nCol2, SCROW nRow2, 1392 const ScRangeData::IndexMap& rMap ) 1393 { 1394 for (SCCOL i = nCol1; i <= nCol2 && (ValidCol(i)); i++) 1395 { 1396 aCol[i].ReplaceRangeNamesInUse( nRow1, nRow2, rMap ); 1397 } 1398 } 1399 1400 void ScTable::ExtendPrintArea( OutputDevice* pDev, 1401 SCCOL /* nStartCol */, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow ) 1402 { 1403 if ( !pColFlags || !pRowFlags ) 1404 { 1405 DBG_ERROR("keine ColInfo oder RowInfo in ExtendPrintArea"); 1406 return; 1407 } 1408 1409 Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP ); 1410 double nPPTX = aPix1000.X() / 1000.0; 1411 double nPPTY = aPix1000.Y() / 1000.0; 1412 1413 // First, mark those columns that we need to skip i.e. hidden and empty columns. 1414 1415 ScFlatBoolColSegments aSkipCols; 1416 aSkipCols.setInsertFromBack(true); // speed optimazation. 1417 aSkipCols.setFalse(0, MAXCOL); 1418 for (SCCOL i = 0; i <= MAXCOL; ++i) 1419 { 1420 SCCOL nLastCol = i; 1421 if (ColHidden(i, NULL, &nLastCol)) 1422 { 1423 // Columns are hidden in this range. 1424 aSkipCols.setTrue(i, nLastCol); 1425 } 1426 else 1427 { 1428 // These columns are visible. Check for empty columns. 1429 for (SCCOL j = i; j <= nLastCol; ++j) 1430 { 1431 if (aCol[j].GetCellCount() == 0) 1432 // empty 1433 aSkipCols.setTrue(j,j); 1434 } 1435 } 1436 i = nLastCol; 1437 } 1438 1439 ScFlatBoolColSegments::RangeData aColData; 1440 for (SCCOL nCol = rEndCol; nCol >= 0; --nCol) 1441 { 1442 if (!aSkipCols.getRangeData(nCol, aColData)) 1443 // Failed to get the data. This should never happen! 1444 return; 1445 1446 if (aColData.mbValue) 1447 { 1448 // Skip these columns. 1449 nCol = aColData.mnCol1; // move toward 0. 1450 continue; 1451 } 1452 1453 // These are visible and non-empty columns. 1454 for (SCCOL nDataCol = nCol; 0 <= nDataCol && nDataCol >= aColData.mnCol1; --nDataCol) 1455 { 1456 SCCOL nPrintCol = nDataCol; 1457 VisibleDataCellIterator aIter(*mpHiddenRows, aCol[nDataCol]); 1458 ScBaseCell* pCell = aIter.reset(nStartRow); 1459 if (!pCell) 1460 // No visible cells found in this column. Skip it. 1461 continue; 1462 1463 while (pCell) 1464 { 1465 SCCOL nNewCol = nDataCol; 1466 SCROW nRow = aIter.getRow(); 1467 if (nRow > nEndRow) 1468 // Went past the last row position. Bail out. 1469 break; 1470 1471 MaybeAddExtraColumn(nNewCol, nRow, pDev, nPPTX, nPPTY); 1472 if (nNewCol > nPrintCol) 1473 nPrintCol = nNewCol; 1474 pCell = aIter.next(); 1475 } 1476 1477 if (nPrintCol > rEndCol) 1478 // Make sure we don't shrink the print area. 1479 rEndCol = nPrintCol; 1480 } 1481 nCol = aColData.mnCol1; // move toward 0. 1482 } 1483 } 1484 1485 void ScTable::MaybeAddExtraColumn(SCCOL& rCol, SCROW nRow, OutputDevice* pDev, double nPPTX, double nPPTY) 1486 { 1487 ScBaseCell* pCell = aCol[rCol].GetCell(nRow); 1488 if (!pCell || !pCell->HasStringData()) 1489 return; 1490 1491 bool bFormula = false; //! ueberge 1492 long nPixel = pCell->GetTextWidth(); 1493 1494 // Breite bereits im Idle-Handler berechnet? 1495 if ( TEXTWIDTH_DIRTY == nPixel ) 1496 { 1497 ScNeededSizeOptions aOptions; 1498 aOptions.bTotalSize = sal_True; 1499 aOptions.bFormula = bFormula; 1500 aOptions.bSkipMerged = sal_False; 1501 1502 Fraction aZoom(1,1); 1503 nPixel = aCol[rCol].GetNeededSize( 1504 nRow, pDev, nPPTX, nPPTY, aZoom, aZoom, true, aOptions ); 1505 pCell->SetTextWidth( (sal_uInt16)nPixel ); 1506 } 1507 1508 long nTwips = (long) (nPixel / nPPTX); 1509 long nDocW = GetColWidth( rCol ); 1510 1511 long nMissing = nTwips - nDocW; 1512 if ( nMissing > 0 ) 1513 { 1514 // look at alignment 1515 1516 const ScPatternAttr* pPattern = GetPattern( rCol, nRow ); 1517 const SfxItemSet* pCondSet = NULL; 1518 if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() ) 1519 pCondSet = pDocument->GetCondResult( rCol, nRow, nTab ); 1520 1521 SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&) 1522 pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue(); 1523 if ( eHorJust == SVX_HOR_JUSTIFY_CENTER ) 1524 nMissing /= 2; // distributed into both directions 1525 else 1526 { 1527 // STANDARD is LEFT (only text is handled here) 1528 bool bRight = ( eHorJust == SVX_HOR_JUSTIFY_RIGHT ); 1529 if ( IsLayoutRTL() ) 1530 bRight = !bRight; 1531 if ( bRight ) 1532 nMissing = 0; // extended only to the left (logical) 1533 } 1534 } 1535 1536 SCCOL nNewCol = rCol; 1537 while (nMissing > 0 && nNewCol < MAXCOL) 1538 { 1539 ScBaseCell* pNextCell = aCol[nNewCol+1].GetCell(nRow); 1540 if (pNextCell && pNextCell->GetCellType() != CELLTYPE_NOTE) 1541 // Cell content in a next column ends display of this string. 1542 nMissing = 0; 1543 else 1544 nMissing -= GetColWidth(++nNewCol); 1545 } 1546 rCol = nNewCol; 1547 } 1548 1549 void ScTable::DoColResize( SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd ) 1550 { 1551 for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++) 1552 aCol[nCol].Resize(aCol[nCol].GetCellCount() + nAdd); 1553 } 1554 1555 #define SET_PRINTRANGE( p1, p2 ) \ 1556 if ( (p2) ) \ 1557 { \ 1558 if ( (p1) ) \ 1559 *(p1) = *(p2); \ 1560 else \ 1561 (p1) = new ScRange( *(p2) ); \ 1562 } \ 1563 else \ 1564 DELETEZ( (p1) ) 1565 1566 void ScTable::SetRepeatColRange( const ScRange* pNew ) 1567 { 1568 SET_PRINTRANGE( pRepeatColRange, pNew ); 1569 1570 if (IsStreamValid()) 1571 SetStreamValid(sal_False); 1572 } 1573 1574 void ScTable::SetRepeatRowRange( const ScRange* pNew ) 1575 { 1576 SET_PRINTRANGE( pRepeatRowRange, pNew ); 1577 1578 if (IsStreamValid()) 1579 SetStreamValid(sal_False); 1580 } 1581 1582 void ScTable::ClearPrintRanges() 1583 { 1584 aPrintRanges.clear(); 1585 bPrintEntireSheet = sal_False; 1586 InvalidatePageBreaks(); // #i117952# forget page breaks for an old print range 1587 1588 if (IsStreamValid()) 1589 SetStreamValid(sal_False); 1590 } 1591 1592 void ScTable::AddPrintRange( const ScRange& rNew ) 1593 { 1594 bPrintEntireSheet = sal_False; 1595 if( aPrintRanges.size() < 0xFFFF ) 1596 aPrintRanges.push_back( rNew ); 1597 1598 if (IsStreamValid()) 1599 SetStreamValid(sal_False); 1600 } 1601 1602 //UNUSED2009-05 void ScTable::SetPrintRange( const ScRange& rNew ) 1603 //UNUSED2009-05 { 1604 //UNUSED2009-05 ClearPrintRanges(); 1605 //UNUSED2009-05 AddPrintRange( rNew ); 1606 //UNUSED2009-05 } 1607 1608 void ScTable::SetPrintEntireSheet() 1609 { 1610 if( !IsPrintEntireSheet() ) 1611 { 1612 ClearPrintRanges(); 1613 bPrintEntireSheet = sal_True; 1614 } 1615 } 1616 1617 const ScRange* ScTable::GetPrintRange(sal_uInt16 nPos) const 1618 { 1619 return (nPos < GetPrintRangeCount()) ? &aPrintRanges[ nPos ] : NULL; 1620 } 1621 1622 void ScTable::FillPrintSaver( ScPrintSaverTab& rSaveTab ) const 1623 { 1624 rSaveTab.SetAreas( aPrintRanges, bPrintEntireSheet ); 1625 rSaveTab.SetRepeat( pRepeatColRange, pRepeatRowRange ); 1626 } 1627 1628 void ScTable::RestorePrintRanges( const ScPrintSaverTab& rSaveTab ) 1629 { 1630 aPrintRanges = rSaveTab.GetPrintRanges(); 1631 bPrintEntireSheet = rSaveTab.IsEntireSheet(); 1632 SetRepeatColRange( rSaveTab.GetRepeatCol() ); 1633 SetRepeatRowRange( rSaveTab.GetRepeatRow() ); 1634 1635 InvalidatePageBreaks(); // #i117952# forget page breaks for an old print range 1636 UpdatePageBreaks(NULL); 1637 } 1638 1639 SCROW ScTable::VisibleDataCellIterator::ROW_NOT_FOUND = -1; 1640 1641 ScTable::VisibleDataCellIterator::VisibleDataCellIterator(ScFlatBoolRowSegments& rRowSegs, ScColumn& rColumn) : 1642 mrRowSegs(rRowSegs), 1643 mrColumn(rColumn), 1644 mpCell(NULL), 1645 mnCurRow(ROW_NOT_FOUND), 1646 mnUBound(ROW_NOT_FOUND) 1647 { 1648 } 1649 1650 ScTable::VisibleDataCellIterator::~VisibleDataCellIterator() 1651 { 1652 } 1653 1654 ScBaseCell* ScTable::VisibleDataCellIterator::reset(SCROW nRow) 1655 { 1656 if (nRow > MAXROW) 1657 { 1658 mnCurRow = ROW_NOT_FOUND; 1659 return NULL; 1660 } 1661 1662 ScFlatBoolRowSegments::RangeData aData; 1663 if (!mrRowSegs.getRangeData(nRow, aData)) 1664 { 1665 mnCurRow = ROW_NOT_FOUND; 1666 return NULL; 1667 } 1668 1669 if (!aData.mbValue) 1670 { 1671 // specified row is visible. Take it. 1672 mnCurRow = nRow; 1673 mnUBound = aData.mnRow2; 1674 } 1675 else 1676 { 1677 // specified row is not-visible. The first visible row is the start of 1678 // the next segment. 1679 mnCurRow = aData.mnRow2 + 1; 1680 mnUBound = mnCurRow; // get range data on the next iteration. 1681 if (mnCurRow > MAXROW) 1682 { 1683 // Make sure the row doesn't exceed our current limit. 1684 mnCurRow = ROW_NOT_FOUND; 1685 return NULL; 1686 } 1687 } 1688 1689 mpCell = mrColumn.GetCell(mnCurRow); 1690 if (mpCell) 1691 // First visible cell found. 1692 return mpCell; 1693 1694 // Find a first visible cell below this row (if any). 1695 return next(); 1696 } 1697 1698 ScBaseCell* ScTable::VisibleDataCellIterator::next() 1699 { 1700 if (mnCurRow == ROW_NOT_FOUND) 1701 return NULL; 1702 1703 while (mrColumn.GetNextDataPos(mnCurRow)) 1704 { 1705 if (mnCurRow > mnUBound) 1706 { 1707 // We don't know the visibility of this row range. Query it. 1708 ScFlatBoolRowSegments::RangeData aData; 1709 if (!mrRowSegs.getRangeData(mnCurRow, aData)) 1710 { 1711 mnCurRow = ROW_NOT_FOUND; 1712 return NULL; 1713 } 1714 1715 if (aData.mbValue) 1716 { 1717 // This row is invisible. Skip to the last invisible row and 1718 // try again. 1719 mnCurRow = mnUBound = aData.mnRow2; 1720 continue; 1721 } 1722 1723 // This row is visible. 1724 mnUBound = aData.mnRow2; 1725 } 1726 1727 mpCell = mrColumn.GetCell(mnCurRow); 1728 if (mpCell) 1729 return mpCell; 1730 } 1731 mnCurRow = ROW_NOT_FOUND; 1732 return NULL; 1733 } 1734 1735 SCROW ScTable::VisibleDataCellIterator::getRow() const 1736 { 1737 return mnCurRow; 1738 } 1739 1740