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 28 29 // INCLUDE --------------------------------------------------------------- 30 31 #include <map> 32 33 #include <svl/poolcach.hxx> 34 #include <svl/zforlist.hxx> 35 #include <editeng/scripttypeitem.hxx> 36 #include <string.h> 37 38 #include "scitems.hxx" 39 #include "column.hxx" 40 #include "cell.hxx" 41 #include "document.hxx" 42 #include "docpool.hxx" 43 #include "attarray.hxx" 44 #include "patattr.hxx" 45 #include "compiler.hxx" 46 #include "brdcst.hxx" 47 #include "markdata.hxx" 48 #include "detfunc.hxx" // for Notes in Sort/Swap 49 #include "postit.hxx" 50 51 //#pragma optimize ( "", off ) 52 // nur Search ohne Optimierung! 53 54 // STATIC DATA ----------------------------------------------------------- 55 using namespace formula; 56 57 inline sal_Bool IsAmbiguousScriptNonZero( sal_uInt8 nScript ) 58 { 59 //! move to a header file 60 return ( nScript != SCRIPTTYPE_LATIN && 61 nScript != SCRIPTTYPE_ASIAN && 62 nScript != SCRIPTTYPE_COMPLEX && 63 nScript != 0 ); 64 } 65 66 // ----------------------------------------------------------------------------------------- 67 68 69 ScColumn::ScColumn() : 70 nCol( 0 ), 71 nCount( 0 ), 72 nLimit( 0 ), 73 pItems( NULL ), 74 pAttrArray( NULL ), 75 pDocument( NULL ) 76 { 77 } 78 79 80 ScColumn::~ScColumn() 81 { 82 FreeAll(); 83 if (pAttrArray) delete pAttrArray; 84 } 85 86 87 void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc) 88 { 89 nCol = nNewCol; 90 nTab = nNewTab; 91 pDocument = pDoc; 92 pAttrArray = new ScAttrArray( nCol, nTab, pDocument ); 93 } 94 95 96 SCsROW ScColumn::GetNextUnprotected( SCROW nRow, sal_Bool bUp ) const 97 { 98 return pAttrArray->GetNextUnprotected(nRow, bUp); 99 } 100 101 102 sal_uInt16 ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const 103 { 104 // nix:0, mitte:1, unten:2, links:4, oben:8, rechts:16, offen:32 105 if ( !pItems ) 106 return 0; 107 if ( nRow1 == nRow2 ) 108 { 109 SCSIZE nIndex; 110 if ( Search( nRow1, nIndex ) ) 111 { 112 ScBaseCell* pCell = pItems[nIndex].pCell; 113 if ( pCell->GetCellType() == CELLTYPE_FORMULA 114 && ((ScFormulaCell*)pCell)->GetMatrixFlag() ) 115 { 116 ScAddress aOrg( ScAddress::INITIALIZE_INVALID ); 117 return ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg ); 118 } 119 } 120 return 0; 121 } 122 else 123 { 124 ScAddress aOrg( ScAddress::INITIALIZE_INVALID ); 125 sal_Bool bOpen = sal_False; 126 sal_uInt16 nEdges = 0; 127 SCSIZE nIndex; 128 Search( nRow1, nIndex ); 129 while ( nIndex < nCount && pItems[nIndex].nRow <= nRow2 ) 130 { 131 ScBaseCell* pCell = pItems[nIndex].pCell; 132 if ( pCell->GetCellType() == CELLTYPE_FORMULA 133 && ((ScFormulaCell*)pCell)->GetMatrixFlag() ) 134 { 135 nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg ); 136 if ( nEdges ) 137 { 138 if ( nEdges & 8 ) 139 bOpen = sal_True; // obere Kante oeffnet, weitersehen 140 else if ( !bOpen ) 141 return nEdges | 32; // es gibt was, was nicht geoeffnet wurde 142 else if ( nEdges & 1 ) 143 return nEdges; // mittendrin 144 // (nMask & 16 und (4 und nicht 16)) oder 145 // (nMask & 4 und (16 und nicht 4)) 146 if ( ((nMask & 16) && (nEdges & 4) && !(nEdges & 16)) 147 || ((nMask & 4) && (nEdges & 16) && !(nEdges & 4)) ) 148 return nEdges; // nur linke/rechte Kante 149 if ( nEdges & 2 ) 150 bOpen = sal_False; // untere Kante schliesst 151 } 152 } 153 nIndex++; 154 } 155 if ( bOpen ) 156 nEdges |= 32; // es geht noch weiter 157 return nEdges; 158 } 159 } 160 161 162 sal_Bool ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const 163 { 164 if ( rMark.IsMultiMarked() ) 165 { 166 sal_Bool bFound = sal_False; 167 168 ScAddress aOrg( ScAddress::INITIALIZE_INVALID ); 169 ScAddress aCurOrg( ScAddress::INITIALIZE_INVALID ); 170 SCROW nTop, nBottom; 171 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol ); 172 while ( !bFound && aMarkIter.Next( nTop, nBottom ) ) 173 { 174 sal_Bool bOpen = sal_False; 175 sal_uInt16 nEdges; 176 SCSIZE nIndex; 177 Search( nTop, nIndex ); 178 while ( !bFound && nIndex < nCount && pItems[nIndex].nRow <= nBottom ) 179 { 180 ScBaseCell* pCell = pItems[nIndex].pCell; 181 if ( pCell->GetCellType() == CELLTYPE_FORMULA 182 && ((ScFormulaCell*)pCell)->GetMatrixFlag() ) 183 { 184 nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg ); 185 if ( nEdges ) 186 { 187 if ( nEdges & 8 ) 188 bOpen = sal_True; // obere Kante oeffnet, weitersehen 189 else if ( !bOpen ) 190 return sal_True; // es gibt was, was nicht geoeffnet wurde 191 else if ( nEdges & 1 ) 192 bFound = sal_True; // mittendrin, alles selektiert? 193 // (4 und nicht 16) oder (16 und nicht 4) 194 if ( (((nEdges & 4) | 16) ^ ((nEdges & 16) | 4)) ) 195 bFound = sal_True; // nur linke/rechte Kante, alles selektiert? 196 if ( nEdges & 2 ) 197 bOpen = sal_False; // untere Kante schliesst 198 199 if ( bFound ) 200 { // alles selektiert? 201 if ( aCurOrg != aOrg ) 202 { // neue Matrix zu pruefen? 203 aCurOrg = aOrg; 204 ScFormulaCell* pFCell; 205 if ( ((ScFormulaCell*)pCell)->GetMatrixFlag() 206 == MM_REFERENCE ) 207 pFCell = (ScFormulaCell*) pDocument->GetCell( aOrg ); 208 else 209 pFCell = (ScFormulaCell*)pCell; 210 SCCOL nC; 211 SCROW nR; 212 pFCell->GetMatColsRows( nC, nR ); 213 ScRange aRange( aOrg, ScAddress( 214 aOrg.Col() + nC - 1, aOrg.Row() + nR - 1, 215 aOrg.Tab() ) ); 216 if ( rMark.IsAllMarked( aRange ) ) 217 bFound = sal_False; 218 } 219 else 220 bFound = sal_False; // war schon 221 } 222 } 223 } 224 nIndex++; 225 } 226 if ( bOpen ) 227 return sal_True; 228 } 229 return bFound; 230 } 231 else 232 return sal_False; 233 } 234 235 236 //UNUSED2009-05 sal_Bool ScColumn::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes, 237 //UNUSED2009-05 sal_Bool bLeft, sal_Bool bRight ) const 238 //UNUSED2009-05 { 239 //UNUSED2009-05 return pAttrArray->HasLines( nRow1, nRow2, rSizes, bLeft, bRight ); 240 //UNUSED2009-05 } 241 242 243 bool ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const 244 { 245 return pAttrArray->HasAttrib( nRow1, nRow2, nMask ); 246 } 247 248 249 sal_Bool ScColumn::HasAttribSelection( const ScMarkData& rMark, sal_uInt16 nMask ) const 250 { 251 sal_Bool bFound = sal_False; 252 253 SCROW nTop; 254 SCROW nBottom; 255 256 if (rMark.IsMultiMarked()) 257 { 258 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol ); 259 while (aMarkIter.Next( nTop, nBottom ) && !bFound) 260 { 261 if (pAttrArray->HasAttrib( nTop, nBottom, nMask )) 262 bFound = sal_True; 263 } 264 } 265 266 return bFound; 267 } 268 269 270 sal_Bool ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow, 271 SCCOL& rPaintCol, SCROW& rPaintRow, 272 sal_Bool bRefresh, sal_Bool bAttrs ) 273 { 274 return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh, bAttrs ); 275 } 276 277 278 void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, sal_Bool bDeep ) const 279 { 280 SCROW nTop; 281 SCROW nBottom; 282 283 if ( rMark.IsMultiMarked() ) 284 { 285 const ScMarkArray* pArray = rMark.GetArray() + nCol; 286 if ( pArray->HasMarks() ) 287 { 288 ScMarkArrayIter aMarkIter( pArray ); 289 while (aMarkIter.Next( nTop, nBottom )) 290 pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep ); 291 } 292 } 293 } 294 295 296 void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, sal_Bool bDeep ) const 297 { 298 pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep ); 299 } 300 301 302 void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, 303 ScLineFlags& rFlags, 304 SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) const 305 { 306 pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight ); 307 } 308 309 310 void ScColumn::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner, 311 SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) 312 { 313 pAttrArray->ApplyBlockFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight ); 314 } 315 316 317 const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const 318 { 319 return pAttrArray->GetPattern( nRow ); 320 } 321 322 323 const SfxPoolItem* ScColumn::GetAttr( SCROW nRow, sal_uInt16 nWhich ) const 324 { 325 return &pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich); 326 } 327 328 329 const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const 330 { 331 ::std::map< const ScPatternAttr*, size_t > aAttrMap; 332 const ScPatternAttr* pMaxPattern = 0; 333 size_t nMaxCount = 0; 334 335 ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow ); 336 const ScPatternAttr* pPattern; 337 SCROW nAttrRow1 = 0, nAttrRow2 = 0; 338 339 while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != 0 ) 340 { 341 size_t& rnCount = aAttrMap[ pPattern ]; 342 rnCount += (nAttrRow2 - nAttrRow1 + 1); 343 if( rnCount > nMaxCount ) 344 { 345 pMaxPattern = pPattern; 346 nMaxCount = rnCount; 347 } 348 } 349 350 return pMaxPattern; 351 } 352 353 354 sal_uLong ScColumn::GetNumberFormat( SCROW nRow ) const 355 { 356 return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() ); 357 } 358 359 360 SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark ) 361 { 362 SCROW nTop = 0; 363 SCROW nBottom = 0; 364 sal_Bool bFound = sal_False; 365 366 if ( rMark.IsMultiMarked() ) 367 { 368 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol ); 369 while (aMarkIter.Next( nTop, nBottom )) 370 { 371 pAttrArray->ApplyCacheArea( nTop, nBottom, pCache ); 372 bFound = sal_True; 373 } 374 } 375 376 if (!bFound) 377 return -1; 378 else if (nTop==0 && nBottom==MAXROW) 379 return 0; 380 else 381 return nBottom; 382 } 383 384 385 void ScColumn::ChangeSelectionIndent( sal_Bool bIncrement, const ScMarkData& rMark ) 386 { 387 SCROW nTop; 388 SCROW nBottom; 389 390 if ( pAttrArray && rMark.IsMultiMarked() ) 391 { 392 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol ); 393 while (aMarkIter.Next( nTop, nBottom )) 394 pAttrArray->ChangeIndent(nTop, nBottom, bIncrement); 395 } 396 } 397 398 399 void ScColumn::ClearSelectionItems( const sal_uInt16* pWhich,const ScMarkData& rMark ) 400 { 401 SCROW nTop; 402 SCROW nBottom; 403 404 if ( pAttrArray && rMark.IsMultiMarked() ) 405 { 406 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol ); 407 while (aMarkIter.Next( nTop, nBottom )) 408 pAttrArray->ClearItems(nTop, nBottom, pWhich); 409 } 410 } 411 412 413 void ScColumn::DeleteSelection( sal_uInt16 nDelFlag, const ScMarkData& rMark ) 414 { 415 SCROW nTop; 416 SCROW nBottom; 417 418 if ( rMark.IsMultiMarked() ) 419 { 420 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol ); 421 while (aMarkIter.Next( nTop, nBottom )) 422 DeleteArea(nTop, nBottom, nDelFlag); 423 } 424 } 425 426 427 void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr ) 428 { 429 const SfxItemSet* pSet = &rPatAttr.GetItemSet(); 430 SfxItemPoolCache aCache( pDocument->GetPool(), pSet ); 431 432 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow ); 433 434 // sal_True = alten Eintrag behalten 435 436 ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, sal_True ); 437 ScDocumentPool::CheckRef( *pPattern ); 438 ScDocumentPool::CheckRef( *pNewPattern ); 439 440 if (pNewPattern != pPattern) 441 pAttrArray->SetPattern( nRow, pNewPattern ); 442 } 443 444 445 void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr ) 446 { 447 const SfxItemSet* pSet = &rPatAttr.GetItemSet(); 448 SfxItemPoolCache aCache( pDocument->GetPool(), pSet ); 449 pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache ); 450 } 451 452 453 void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange, 454 const ScPatternAttr& rPattern, short nNewType ) 455 { 456 const SfxItemSet* pSet = &rPattern.GetItemSet(); 457 SfxItemPoolCache aCache( pDocument->GetPool(), pSet ); 458 SvNumberFormatter* pFormatter = pDocument->GetFormatTable(); 459 SCROW nEndRow = rRange.aEnd.Row(); 460 for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ ) 461 { 462 SCROW nRow1, nRow2; 463 const ScPatternAttr* pPattern = pAttrArray->GetPatternRange( 464 nRow1, nRow2, nRow ); 465 sal_uLong nFormat = pPattern->GetNumberFormat( pFormatter ); 466 short nOldType = pFormatter->GetType( nFormat ); 467 if ( nOldType == nNewType || pFormatter->IsCompatible( nOldType, nNewType ) ) 468 nRow = nRow2; 469 else 470 { 471 SCROW nNewRow1 = Max( nRow1, nRow ); 472 SCROW nNewRow2 = Min( nRow2, nEndRow ); 473 pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache ); 474 nRow = nNewRow2; 475 } 476 } 477 } 478 479 480 void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle ) 481 { 482 const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow); 483 ScPatternAttr* pNewPattern = new ScPatternAttr(*pPattern); 484 if (pNewPattern) 485 { 486 pNewPattern->SetStyleSheet((ScStyleSheet*)&rStyle); 487 pAttrArray->SetPattern(nRow, pNewPattern, sal_True); 488 delete pNewPattern; 489 } 490 } 491 492 493 void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle ) 494 { 495 pAttrArray->ApplyStyleArea(nStartRow, nEndRow, (ScStyleSheet*)&rStyle); 496 } 497 498 499 void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark) 500 { 501 SCROW nTop; 502 SCROW nBottom; 503 504 if ( rMark.IsMultiMarked() ) 505 { 506 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol ); 507 while (aMarkIter.Next( nTop, nBottom )) 508 pAttrArray->ApplyStyleArea(nTop, nBottom, (ScStyleSheet*)&rStyle); 509 } 510 } 511 512 513 void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark, 514 const SvxBorderLine* pLine, sal_Bool bColorOnly ) 515 { 516 if ( bColorOnly && !pLine ) 517 return; 518 519 SCROW nTop; 520 SCROW nBottom; 521 522 if (rMark.IsMultiMarked()) 523 { 524 ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol ); 525 while (aMarkIter.Next( nTop, nBottom )) 526 pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly ); 527 } 528 } 529 530 531 const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const 532 { 533 return pAttrArray->GetPattern( nRow )->GetStyleSheet(); 534 } 535 536 537 const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, sal_Bool& rFound ) const 538 { 539 rFound = sal_False; 540 if (!rMark.IsMultiMarked()) 541 { 542 DBG_ERROR("ScColumn::GetSelectionStyle ohne Selektion"); 543 return NULL; 544 } 545 546 sal_Bool bEqual = sal_True; 547 548 const ScStyleSheet* pStyle = NULL; 549 const ScStyleSheet* pNewStyle; 550 551 ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol ); 552 SCROW nTop; 553 SCROW nBottom; 554 while (bEqual && aMarkIter.Next( nTop, nBottom )) 555 { 556 ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom ); 557 SCROW nRow; 558 SCROW nDummy; 559 const ScPatternAttr* pPattern; 560 while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL) 561 { 562 pNewStyle = pPattern->GetStyleSheet(); 563 rFound = sal_True; 564 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) ) 565 bEqual = sal_False; // unterschiedliche 566 pStyle = pNewStyle; 567 } 568 } 569 570 return bEqual ? pStyle : NULL; 571 } 572 573 574 const ScStyleSheet* ScColumn::GetAreaStyle( sal_Bool& rFound, SCROW nRow1, SCROW nRow2 ) const 575 { 576 rFound = sal_False; 577 578 sal_Bool bEqual = sal_True; 579 580 const ScStyleSheet* pStyle = NULL; 581 const ScStyleSheet* pNewStyle; 582 583 ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 ); 584 SCROW nRow; 585 SCROW nDummy; 586 const ScPatternAttr* pPattern; 587 while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL) 588 { 589 pNewStyle = pPattern->GetStyleSheet(); 590 rFound = sal_True; 591 if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) ) 592 bEqual = sal_False; // unterschiedliche 593 pStyle = pNewStyle; 594 } 595 596 return bEqual ? pStyle : NULL; 597 } 598 599 void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset ) 600 { 601 pAttrArray->FindStyleSheet( pStyleSheet, rUsedRows, bReset ); 602 } 603 604 sal_Bool ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, sal_Bool bGatherAllStyles ) const 605 { 606 return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles ); 607 } 608 609 610 sal_Bool ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags ) 611 { 612 return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags ); 613 } 614 615 616 sal_Bool ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags ) 617 { 618 return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags ); 619 } 620 621 622 void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich ) 623 { 624 pAttrArray->ClearItems( nStartRow, nEndRow, pWhich ); 625 } 626 627 628 void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, sal_Bool bPutToPool ) 629 { 630 pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool ); 631 } 632 633 634 void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow, 635 const ScPatternAttr& rPatAttr, sal_Bool bPutToPool ) 636 { 637 pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, bPutToPool ); 638 } 639 640 641 void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr ) 642 { 643 // um nur ein neues SetItem zu erzeugen, brauchen wir keinen SfxItemPoolCache. 644 //! Achtung: der SfxItemPoolCache scheint zuviele Refs fuer das neue SetItem zu erzeugen ?? 645 646 ScDocumentPool* pDocPool = pDocument->GetPool(); 647 648 const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow ); 649 ScPatternAttr* pTemp = new ScPatternAttr(*pOldPattern); 650 pTemp->GetItemSet().Put(rAttr); 651 const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pDocPool->Put( *pTemp ); 652 653 if ( pNewPattern != pOldPattern ) 654 pAttrArray->SetPattern( nRow, pNewPattern ); 655 else 656 pDocPool->Remove( *pNewPattern ); // ausser Spesen nichts gewesen 657 658 delete pTemp; 659 660 // alte Version mit SfxItemPoolCache: 661 #if 0 662 SfxItemPoolCache aCache( pDocument->GetPool(), &rAttr ); 663 664 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow ); 665 666 // sal_True = alten Eintrag behalten 667 668 ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, sal_True ); 669 ScDocumentPool::CheckRef( *pPattern ); 670 ScDocumentPool::CheckRef( *pNewPattern ); 671 672 if (pNewPattern != pPattern) 673 pAttrArray->SetPattern( nRow, pNewPattern ); 674 #endif 675 } 676 677 #ifdef _MSC_VER 678 #pragma optimize ( "", off ) 679 #endif 680 681 682 sal_Bool ScColumn::Search( SCROW nRow, SCSIZE& nIndex ) const 683 { 684 if ( !pItems || !nCount ) 685 { 686 nIndex = 0; 687 return sal_False; 688 } 689 SCROW nMinRow = pItems[0].nRow; 690 if ( nRow <= nMinRow ) 691 { 692 nIndex = 0; 693 return nRow == nMinRow; 694 } 695 SCROW nMaxRow = pItems[nCount-1].nRow; 696 if ( nRow >= nMaxRow ) 697 { 698 if ( nRow == nMaxRow ) 699 { 700 nIndex = nCount - 1; 701 return sal_True; 702 } 703 else 704 { 705 nIndex = nCount; 706 return sal_False; 707 } 708 } 709 710 long nOldLo, nOldHi; 711 long nLo = nOldLo = 0; 712 long nHi = nOldHi = Min(static_cast<long>(nCount)-1, static_cast<long>(nRow) ); 713 long i = 0; 714 sal_Bool bFound = sal_False; 715 // quite continuous distribution? => interpolating search 716 sal_Bool bInterpol = (static_cast<SCSIZE>(nMaxRow - nMinRow) < nCount * 2); 717 SCROW nR; 718 719 while ( !bFound && nLo <= nHi ) 720 { 721 if ( !bInterpol || nHi - nLo < 3 ) 722 i = (nLo+nHi) / 2; // no effort, no division by zero 723 else 724 { // interpolating search 725 long nLoRow = pItems[nLo].nRow; // no unsigned underflow upon substraction 726 i = nLo + (long)((long)(nRow - nLoRow) * (nHi - nLo) 727 / (pItems[nHi].nRow - nLoRow)); 728 if ( i < 0 || static_cast<SCSIZE>(i) >= nCount ) 729 { // oops ... 730 i = (nLo+nHi) / 2; 731 bInterpol = sal_False; 732 } 733 } 734 nR = pItems[i].nRow; 735 if ( nR < nRow ) 736 { 737 nLo = i+1; 738 if ( bInterpol ) 739 { 740 if ( nLo <= nOldLo ) 741 bInterpol = sal_False; 742 else 743 nOldLo = nLo; 744 } 745 } 746 else 747 { 748 if ( nR > nRow ) 749 { 750 nHi = i-1; 751 if ( bInterpol ) 752 { 753 if ( nHi >= nOldHi ) 754 bInterpol = sal_False; 755 else 756 nOldHi = nHi; 757 } 758 } 759 else 760 bFound = sal_True; 761 } 762 } 763 if (bFound) 764 nIndex = static_cast<SCSIZE>(i); 765 else 766 nIndex = static_cast<SCSIZE>(nLo); // rear index 767 return bFound; 768 } 769 770 #ifdef _MSC_VER 771 #pragma optimize ( "", on ) 772 #endif 773 774 775 ScBaseCell* ScColumn::GetCell( SCROW nRow ) const 776 { 777 SCSIZE nIndex; 778 if (Search(nRow, nIndex)) 779 return pItems[nIndex].pCell; 780 return NULL; 781 } 782 783 784 void ScColumn::Resize( SCSIZE nSize ) 785 { 786 if (nSize > sal::static_int_cast<SCSIZE>(MAXROWCOUNT)) 787 nSize = MAXROWCOUNT; 788 if (nSize < nCount) 789 nSize = nCount; 790 791 ColEntry* pNewItems; 792 if (nSize) 793 { 794 SCSIZE nNewSize = nSize + COLUMN_DELTA - 1; 795 nNewSize -= nNewSize % COLUMN_DELTA; 796 nLimit = nNewSize; 797 pNewItems = new ColEntry[nLimit]; 798 } 799 else 800 { 801 nLimit = 0; 802 pNewItems = NULL; 803 } 804 if (pItems) 805 { 806 if (pNewItems) 807 memmove( pNewItems, pItems, nCount * sizeof(ColEntry) ); 808 delete[] pItems; 809 } 810 pItems = pNewItems; 811 } 812 813 // SwapRow zum Sortieren 814 815 namespace { 816 817 /** Moves broadcaster from old cell to new cell if exists, otherwise creates a new note cell. */ 818 void lclTakeBroadcaster( ScBaseCell*& rpCell, SvtBroadcaster* pBC ) 819 { 820 if( pBC ) 821 { 822 if( rpCell ) 823 rpCell->TakeBroadcaster( pBC ); 824 else 825 rpCell = new ScNoteCell( pBC ); 826 } 827 } 828 829 } // namespace 830 831 void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2) 832 { 833 /* Simple swap of cell pointers does not work if broadcasters exist (crash 834 if cell broadcasts directly or indirectly to itself). While swapping 835 the cells, broadcasters have to remain at old positions! */ 836 837 /* While cloning cells, do not clone notes, but move note pointers to new 838 cells. This prevents creation of new caption drawing objects for every 839 swap operation while sorting. */ 840 841 ScBaseCell* pCell1 = 0; 842 SCSIZE nIndex1; 843 if ( Search( nRow1, nIndex1 ) ) 844 pCell1 = pItems[nIndex1].pCell; 845 846 ScBaseCell* pCell2 = 0; 847 SCSIZE nIndex2; 848 if ( Search( nRow2, nIndex2 ) ) 849 pCell2 = pItems[nIndex2].pCell; 850 851 // no cells found, nothing to do 852 if ( !pCell1 && !pCell2 ) 853 return ; 854 855 // swap variables if first cell is empty, to save some code below 856 if ( !pCell1 ) 857 { 858 ::std::swap( nRow1, nRow2 ); 859 ::std::swap( nIndex1, nIndex2 ); 860 ::std::swap( pCell1, pCell2 ); 861 } 862 863 // from here: first cell (pCell1, nIndex1) exists always 864 865 ScAddress aPos1( nCol, nRow1, nTab ); 866 ScAddress aPos2( nCol, nRow2, nTab ); 867 868 CellType eType1 = pCell1->GetCellType(); 869 CellType eType2 = pCell2 ? pCell2->GetCellType() : CELLTYPE_NONE; 870 871 ScFormulaCell* pFmlaCell1 = (eType1 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0; 872 ScFormulaCell* pFmlaCell2 = (eType2 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell2 ) : 0; 873 874 // simple swap if no formula cells present 875 if ( !pFmlaCell1 && !pFmlaCell2 ) 876 { 877 // remember cell broadcasters, must remain at old position 878 SvtBroadcaster* pBC1 = pCell1->ReleaseBroadcaster(); 879 880 if ( pCell2 ) 881 { 882 /* Both cells exist, no formula cells involved, a simple swap can 883 be performed (but keep broadcasters and notes at old position). */ 884 pItems[nIndex1].pCell = pCell2; 885 pItems[nIndex2].pCell = pCell1; 886 887 SvtBroadcaster* pBC2 = pCell2->ReleaseBroadcaster(); 888 pCell1->TakeBroadcaster( pBC2 ); 889 pCell2->TakeBroadcaster( pBC1 ); 890 } 891 else 892 { 893 ScNoteCell* pDummyCell = pBC1 ? new ScNoteCell( pBC1 ) : 0; 894 if ( pDummyCell ) 895 { 896 // insert dummy note cell (without note) containing old broadcaster 897 pItems[nIndex1].pCell = pDummyCell; 898 } 899 else 900 { 901 // remove ColEntry at old position 902 --nCount; 903 memmove( &pItems[nIndex1], &pItems[nIndex1 + 1], (nCount - nIndex1) * sizeof(ColEntry) ); 904 pItems[nCount].nRow = 0; 905 pItems[nCount].pCell = 0; 906 } 907 908 // insert ColEntry at new position 909 Insert( nRow2, pCell1 ); 910 } 911 912 return; 913 } 914 915 // from here: at least one of the cells is a formula cell 916 917 /* Never move any array formulas. Disabling sort if parts of array 918 formulas are contained is done at UI. */ 919 if ( (pFmlaCell1 && (pFmlaCell1->GetMatrixFlag() != 0)) || (pFmlaCell2 && (pFmlaCell2->GetMatrixFlag() != 0)) ) 920 return; 921 922 // do not swap, if formulas are equal 923 if ( pFmlaCell1 && pFmlaCell2 ) 924 { 925 ScTokenArray* pCode1 = pFmlaCell1->GetCode(); 926 ScTokenArray* pCode2 = pFmlaCell2->GetCode(); 927 928 if (pCode1->GetLen() == pCode2->GetLen()) // nicht-UPN 929 { 930 sal_Bool bEqual = sal_True; 931 sal_uInt16 nLen = pCode1->GetLen(); 932 FormulaToken** ppToken1 = pCode1->GetArray(); 933 FormulaToken** ppToken2 = pCode2->GetArray(); 934 for (sal_uInt16 i=0; i<nLen; i++) 935 { 936 if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) || 937 ppToken1[i]->Is3DRef() || ppToken2[i]->Is3DRef() ) 938 { 939 bEqual = sal_False; 940 break; 941 } 942 } 943 944 // do not swap formula cells with equal formulas, but swap notes 945 if (bEqual) 946 { 947 ScPostIt* pNote1 = pCell1->ReleaseNote(); 948 pCell1->TakeNote( pCell2->ReleaseNote() ); 949 pCell2->TakeNote( pNote1 ); 950 return; 951 } 952 } 953 } 954 955 // hier kein UpdateReference wegen #30529# - mitsortiert werden nur noch relative Referenzen 956 // long dy = (long)nRow2 - (long)nRow1; 957 958 /* Create clone of pCell1 at position of pCell2 (pCell1 exists always, see 959 variable swapping above). Do not clone the note, but move pointer of 960 old note to new cell. */ 961 ScBaseCell* pNew2 = pCell1->CloneWithoutNote( *pDocument, aPos2, SC_CLONECELL_ADJUST3DREL ); 962 pNew2->TakeNote( pCell1->ReleaseNote() ); 963 964 /* Create clone of pCell2 at position of pCell1. Do not clone the note, 965 but move pointer of old note to new cell. */ 966 ScBaseCell* pNew1 = 0; 967 if ( pCell2 ) 968 { 969 pNew1 = pCell2->CloneWithoutNote( *pDocument, aPos1, SC_CLONECELL_ADJUST3DREL ); 970 pNew1->TakeNote( pCell2->ReleaseNote() ); 971 } 972 973 // move old broadcasters new cells at the same old position 974 SvtBroadcaster* pBC1 = pCell1->ReleaseBroadcaster(); 975 lclTakeBroadcaster( pNew1, pBC1 ); 976 SvtBroadcaster* pBC2 = pCell2 ? pCell2->ReleaseBroadcaster() : 0; 977 lclTakeBroadcaster( pNew2, pBC2 ); 978 979 /* Insert the new cells. Old cell has to be deleted, if there is no new 980 cell (call to Insert deletes old cell by itself). */ 981 if ( !pNew1 ) 982 Delete( nRow1 ); // deletes pCell1 983 else 984 Insert( nRow1, pNew1 ); // deletes pCell1, inserts pNew1 985 986 if ( pCell2 && !pNew2 ) 987 Delete( nRow2 ); // deletes pCell2 988 else if ( pNew2 ) 989 Insert( nRow2, pNew2 ); // deletes pCell2 (if existing), inserts pNew2 990 } 991 992 993 void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol) 994 { 995 ScBaseCell* pCell1 = 0; 996 SCSIZE nIndex1; 997 if ( Search( nRow, nIndex1 ) ) 998 pCell1 = pItems[nIndex1].pCell; 999 1000 ScBaseCell* pCell2 = 0; 1001 SCSIZE nIndex2; 1002 if ( rCol.Search( nRow, nIndex2 ) ) 1003 pCell2 = rCol.pItems[nIndex2].pCell; 1004 1005 // reverse call if own cell is missing (ensures own existing cell in following code) 1006 if( !pCell1 ) 1007 { 1008 if( pCell2 ) 1009 rCol.SwapCell( nRow, *this ); 1010 return; 1011 } 1012 1013 // from here: own cell (pCell1, nIndex1) exists always 1014 1015 ScFormulaCell* pFmlaCell1 = (pCell1->GetCellType() == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0; 1016 ScFormulaCell* pFmlaCell2 = (pCell2 && (pCell2->GetCellType() == CELLTYPE_FORMULA)) ? static_cast< ScFormulaCell* >( pCell2 ) : 0; 1017 1018 if ( pCell2 ) 1019 { 1020 // Tauschen 1021 pItems[nIndex1].pCell = pCell2; 1022 rCol.pItems[nIndex2].pCell = pCell1; 1023 // Referenzen aktualisieren 1024 SCsCOL dx = rCol.nCol - nCol; 1025 if ( pFmlaCell1 ) 1026 { 1027 ScRange aRange( ScAddress( rCol.nCol, 0, nTab ), 1028 ScAddress( rCol.nCol, MAXROW, nTab ) ); 1029 pFmlaCell1->aPos.SetCol( rCol.nCol ); 1030 pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0); 1031 } 1032 if ( pFmlaCell2 ) 1033 { 1034 ScRange aRange( ScAddress( nCol, 0, nTab ), 1035 ScAddress( nCol, MAXROW, nTab ) ); 1036 pFmlaCell2->aPos.SetCol( nCol ); 1037 pFmlaCell2->UpdateReference(URM_MOVE, aRange, -dx, 0, 0); 1038 } 1039 } 1040 else 1041 { 1042 // Loeschen 1043 --nCount; 1044 memmove( &pItems[nIndex1], &pItems[nIndex1 + 1], (nCount - nIndex1) * sizeof(ColEntry) ); 1045 pItems[nCount].nRow = 0; 1046 pItems[nCount].pCell = 0; 1047 // Referenzen aktualisieren 1048 SCsCOL dx = rCol.nCol - nCol; 1049 if ( pFmlaCell1 ) 1050 { 1051 ScRange aRange( ScAddress( rCol.nCol, 0, nTab ), 1052 ScAddress( rCol.nCol, MAXROW, nTab ) ); 1053 pFmlaCell1->aPos.SetCol( rCol.nCol ); 1054 pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0); 1055 } 1056 // Einfuegen 1057 rCol.Insert(nRow, pCell1); 1058 } 1059 } 1060 1061 1062 sal_Bool ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const 1063 { 1064 if (!IsEmpty()) 1065 { 1066 sal_Bool bTest = sal_True; 1067 if (pItems) 1068 for (SCSIZE i=0; (i<nCount) && bTest; i++) 1069 bTest = (pItems[i].nRow < nStartRow) || (pItems[i].nRow > nEndRow) 1070 || pItems[i].pCell->IsBlank(); 1071 1072 // AttrArray testet nur zusammengefasste 1073 1074 if ((bTest) && (pAttrArray)) 1075 bTest = pAttrArray->TestInsertCol(nStartRow, nEndRow); 1076 1077 //! rausgeschobene Attribute bei Undo beruecksichtigen 1078 1079 return bTest; 1080 } 1081 else 1082 return sal_True; 1083 } 1084 1085 1086 sal_Bool ScColumn::TestInsertRow( SCSIZE nSize ) const 1087 { 1088 // AttrArray only looks for merged cells 1089 1090 if ( pItems && nCount ) 1091 return ( nSize <= sal::static_int_cast<SCSIZE>(MAXROW) && 1092 pItems[nCount-1].nRow <= MAXROW-(SCROW)nSize && pAttrArray->TestInsertRow( nSize ) ); 1093 else 1094 return pAttrArray->TestInsertRow( nSize ); 1095 1096 #if 0 1097 //! rausgeschobene Attribute bei Undo beruecksichtigen 1098 1099 if ( nSize > static_cast<SCSIZE>(MAXROW) ) 1100 return sal_False; 1101 1102 SCSIZE nVis = nCount; 1103 while ( nVis && pItems[nVis-1].pCell->IsBlank() ) 1104 --nVis; 1105 1106 if ( nVis ) 1107 return ( pItems[nVis-1].nRow <= MAXROW-nSize ); 1108 else 1109 return sal_True; 1110 #endif 1111 } 1112 1113 1114 void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize ) 1115 { 1116 pAttrArray->InsertRow( nStartRow, nSize ); 1117 1118 //! Search 1119 1120 if ( !pItems || !nCount ) 1121 return; 1122 1123 SCSIZE i; 1124 Search( nStartRow, i ); 1125 if ( i >= nCount ) 1126 return ; 1127 1128 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc(); 1129 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden 1130 1131 SCSIZE nNewCount = nCount; 1132 sal_Bool bCountChanged = sal_False; 1133 ScAddress aAdr( nCol, 0, nTab ); 1134 ScHint aHint( SC_HINT_DATACHANGED, aAdr, NULL ); // only areas (ScBaseCell* == NULL) 1135 ScAddress& rAddress = aHint.GetAddress(); 1136 // for sparse occupation use single broadcasts, not ranges 1137 sal_Bool bSingleBroadcasts = (((pItems[nCount-1].nRow - pItems[i].nRow) / 1138 (nCount - i)) > 1); 1139 if ( bSingleBroadcasts ) 1140 { 1141 SCROW nLastBroadcast = MAXROW+1; 1142 for ( ; i < nCount; i++) 1143 { 1144 SCROW nOldRow = pItems[i].nRow; 1145 // #43940# Aenderung Quelle broadcasten 1146 if ( nLastBroadcast != nOldRow ) 1147 { // direkt aufeinanderfolgende nicht doppelt broadcasten 1148 rAddress.SetRow( nOldRow ); 1149 pDocument->AreaBroadcast( aHint ); 1150 } 1151 SCROW nNewRow = (pItems[i].nRow += nSize); 1152 // #43940# Aenderung Ziel broadcasten 1153 rAddress.SetRow( nNewRow ); 1154 pDocument->AreaBroadcast( aHint ); 1155 nLastBroadcast = nNewRow; 1156 ScBaseCell* pCell = pItems[i].pCell; 1157 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 1158 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow ); 1159 if ( nNewRow > MAXROW && !bCountChanged ) 1160 { 1161 nNewCount = i; 1162 bCountChanged = sal_True; 1163 } 1164 } 1165 } 1166 else 1167 { 1168 rAddress.SetRow( pItems[i].nRow ); 1169 ScRange aRange( rAddress ); 1170 for ( ; i < nCount; i++) 1171 { 1172 SCROW nNewRow = (pItems[i].nRow += nSize); 1173 ScBaseCell* pCell = pItems[i].pCell; 1174 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 1175 ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow ); 1176 if ( nNewRow > MAXROW && !bCountChanged ) 1177 { 1178 nNewCount = i; 1179 bCountChanged = sal_True; 1180 aRange.aEnd.SetRow( MAXROW ); 1181 } 1182 } 1183 if ( !bCountChanged ) 1184 aRange.aEnd.SetRow( pItems[nCount-1].nRow ); 1185 pDocument->AreaBroadcastInRange( aRange, aHint ); 1186 } 1187 1188 if (bCountChanged) 1189 { 1190 SCSIZE nDelCount = nCount - nNewCount; 1191 ScBaseCell** ppDelCells = new ScBaseCell*[nDelCount]; 1192 SCROW* pDelRows = new SCROW[nDelCount]; 1193 for (i = 0; i < nDelCount; i++) 1194 { 1195 ppDelCells[i] = pItems[nNewCount+i].pCell; 1196 pDelRows[i] = pItems[nNewCount+i].nRow; 1197 } 1198 nCount = nNewCount; 1199 1200 for (i = 0; i < nDelCount; i++) 1201 { 1202 ScBaseCell* pCell = ppDelCells[i]; 1203 DBG_ASSERT( pCell->IsBlank(), "sichtbare Zelle weggeschoben" ); 1204 SvtBroadcaster* pBC = pCell->GetBroadcaster(); 1205 if (pBC) 1206 { 1207 MoveListeners( *pBC, pDelRows[i] - nSize ); 1208 pCell->DeleteBroadcaster(); 1209 pCell->Delete(); 1210 } 1211 } 1212 1213 delete [] pDelRows; 1214 delete [] ppDelCells; 1215 } 1216 1217 pDocument->SetAutoCalc( bOldAutoCalc ); 1218 } 1219 1220 1221 void ScColumn::CopyToClip(SCROW nRow1, SCROW nRow2, ScColumn& rColumn, sal_Bool bKeepScenarioFlags, sal_Bool bCloneNoteCaptions) 1222 { 1223 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray, 1224 bKeepScenarioFlags ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL ); 1225 1226 SCSIZE i; 1227 SCSIZE nBlockCount = 0; 1228 SCSIZE nStartIndex = 0, nEndIndex = 0; 1229 for (i = 0; i < nCount; i++) 1230 if ((pItems[i].nRow >= nRow1) && (pItems[i].nRow <= nRow2)) 1231 { 1232 if (!nBlockCount) 1233 nStartIndex = i; 1234 nEndIndex = i; 1235 ++nBlockCount; 1236 1237 // im Clipboard muessen interpretierte Zellen stehen, um andere Formate 1238 // (Text, Grafik...) erzueugen zu koennen 1239 1240 if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA ) 1241 { 1242 ScFormulaCell* pFCell = (ScFormulaCell*) pItems[i].pCell; 1243 if (pFCell->GetDirty() && pDocument->GetAutoCalc()) 1244 pFCell->Interpret(); 1245 } 1246 } 1247 1248 if (nBlockCount) 1249 { 1250 int nCloneFlags = bCloneNoteCaptions ? SC_CLONECELL_DEFAULT : SC_CLONECELL_NOCAPTION; 1251 rColumn.Resize( rColumn.GetCellCount() + nBlockCount ); 1252 ScAddress aOwnPos( nCol, 0, nTab ); 1253 ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab ); 1254 for (i = nStartIndex; i <= nEndIndex; i++) 1255 { 1256 aOwnPos.SetRow( pItems[i].nRow ); 1257 aDestPos.SetRow( pItems[i].nRow ); 1258 ScBaseCell* pNewCell = pItems[i].pCell->CloneWithNote( aOwnPos, *rColumn.pDocument, aDestPos, nCloneFlags ); 1259 rColumn.Append( aDestPos.Row(), pNewCell ); 1260 } 1261 } 1262 } 1263 1264 1265 void ScColumn::CopyToColumn(SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, sal_Bool bMarked, 1266 ScColumn& rColumn, const ScMarkData* pMarkData, sal_Bool bAsLink ) 1267 { 1268 if (bMarked) 1269 { 1270 SCROW nStart, nEnd; 1271 if (pMarkData && pMarkData->IsMultiMarked()) 1272 { 1273 ScMarkArrayIter aIter( pMarkData->GetArray()+nCol ); 1274 1275 while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 ) 1276 { 1277 if ( nEnd >= nRow1 ) 1278 CopyToColumn( Max(nRow1,nStart), Min(nRow2,nEnd), 1279 nFlags, sal_False, rColumn, pMarkData, bAsLink ); 1280 } 1281 } 1282 else 1283 { 1284 DBG_ERROR("CopyToColumn: bMarked, aber keine Markierung"); 1285 } 1286 return; 1287 } 1288 1289 if ( (nFlags & IDF_ATTRIB) != 0 ) 1290 { 1291 if ( (nFlags & IDF_STYLES) != IDF_STYLES ) 1292 { // StyleSheets im Zieldokument bleiben erhalten 1293 // z.B. DIF und RTF Clipboard-Import 1294 for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ ) 1295 { 1296 const ScStyleSheet* pStyle = 1297 rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet(); 1298 const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow ); 1299 ScPatternAttr* pNewPattern = new ScPatternAttr( *pPattern ); 1300 pNewPattern->SetStyleSheet( (ScStyleSheet*)pStyle ); 1301 rColumn.pAttrArray->SetPattern( nRow, pNewPattern, sal_True ); 1302 delete pNewPattern; 1303 } 1304 } 1305 else 1306 pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray); 1307 } 1308 1309 1310 if ((nFlags & IDF_CONTENTS) != 0) 1311 { 1312 SCSIZE i; 1313 SCSIZE nBlockCount = 0; 1314 SCSIZE nStartIndex = 0, nEndIndex = 0; 1315 for (i = 0; i < nCount; i++) 1316 if ((pItems[i].nRow >= nRow1) && (pItems[i].nRow <= nRow2)) 1317 { 1318 if (!nBlockCount) 1319 nStartIndex = i; 1320 nEndIndex = i; 1321 ++nBlockCount; 1322 } 1323 1324 if (nBlockCount) 1325 { 1326 rColumn.Resize( rColumn.GetCellCount() + nBlockCount ); 1327 ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab ); 1328 for (i = nStartIndex; i <= nEndIndex; i++) 1329 { 1330 aDestPos.SetRow( pItems[i].nRow ); 1331 ScBaseCell* pNew = bAsLink ? 1332 CreateRefCell( rColumn.pDocument, aDestPos, i, nFlags ) : 1333 CloneCell( i, nFlags, *rColumn.pDocument, aDestPos ); 1334 1335 if (pNew) 1336 rColumn.Insert(pItems[i].nRow, pNew); 1337 } 1338 } 1339 } 1340 } 1341 1342 1343 void ScColumn::UndoToColumn(SCROW nRow1, SCROW nRow2, sal_uInt16 nFlags, sal_Bool bMarked, 1344 ScColumn& rColumn, const ScMarkData* pMarkData ) 1345 { 1346 if (nRow1 > 0) 1347 CopyToColumn( 0, nRow1-1, IDF_FORMULA, sal_False, rColumn ); 1348 1349 CopyToColumn( nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData ); //! bMarked ???? 1350 1351 if (nRow2 < MAXROW) 1352 CopyToColumn( nRow2+1, MAXROW, IDF_FORMULA, sal_False, rColumn ); 1353 } 1354 1355 1356 void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const 1357 { 1358 ScDocument& rDestDoc = *rDestCol.pDocument; 1359 ScAddress aOwnPos( nCol, 0, nTab ); 1360 ScAddress aDestPos( rDestCol.nCol, 0, rDestCol.nTab ); 1361 1362 SCSIZE nPosCount = rPosCol.nCount; 1363 for (SCSIZE nPosIndex = 0; nPosIndex < nPosCount; nPosIndex++) 1364 { 1365 aOwnPos.SetRow( rPosCol.pItems[nPosIndex].nRow ); 1366 aDestPos.SetRow( aOwnPos.Row() ); 1367 SCSIZE nThisIndex; 1368 if ( Search( aDestPos.Row(), nThisIndex ) ) 1369 { 1370 ScBaseCell* pNew = pItems[nThisIndex].pCell->CloneWithNote( aOwnPos, rDestDoc, aDestPos ); 1371 rDestCol.Insert( aDestPos.Row(), pNew ); 1372 } 1373 } 1374 1375 // Dummy: 1376 // CopyToColumn( 0,MAXROW, IDF_FORMULA, sal_False, rDestCol, NULL, sal_False ); 1377 } 1378 1379 1380 void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol ) 1381 { 1382 // Dies ist die Szenario-Tabelle, die Daten werden hineinkopiert 1383 1384 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW ); 1385 SCROW nStart = -1, nEnd = -1; 1386 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd ); 1387 while (pPattern) 1388 { 1389 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() ) 1390 { 1391 DeleteArea( nStart, nEnd, IDF_CONTENTS ); 1392 ((ScColumn&)rSrcCol). 1393 CopyToColumn( nStart, nEnd, IDF_CONTENTS, sal_False, *this ); 1394 1395 // UpdateUsed nicht noetig, schon in TestCopyScenario passiert 1396 1397 SCsTAB nDz = nTab - rSrcCol.nTab; 1398 UpdateReference(URM_COPY, nCol, nStart, nTab, 1399 nCol, nEnd, nTab, 1400 0, 0, nDz, NULL); 1401 UpdateCompile(); 1402 } 1403 1404 //! CopyToColumn "const" machen !!! 1405 1406 pPattern = aAttrIter.Next( nStart, nEnd ); 1407 } 1408 } 1409 1410 1411 void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const 1412 { 1413 // Dies ist die Szenario-Tabelle, die Daten werden in die andere kopiert 1414 1415 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW ); 1416 SCROW nStart = -1, nEnd = -1; 1417 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd ); 1418 while (pPattern) 1419 { 1420 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() ) 1421 { 1422 rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS ); 1423 ((ScColumn*)this)-> 1424 CopyToColumn( nStart, nEnd, IDF_CONTENTS, sal_False, rDestCol ); 1425 1426 // UpdateUsed nicht noetig, schon in TestCopyScenario passiert 1427 1428 SCsTAB nDz = rDestCol.nTab - nTab; 1429 rDestCol.UpdateReference(URM_COPY, rDestCol.nCol, nStart, rDestCol.nTab, 1430 rDestCol.nCol, nEnd, rDestCol.nTab, 1431 0, 0, nDz, NULL); 1432 rDestCol.UpdateCompile(); 1433 } 1434 1435 //! CopyToColumn "const" machen !!! 1436 1437 pPattern = aAttrIter.Next( nStart, nEnd ); 1438 } 1439 } 1440 1441 1442 sal_Bool ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const 1443 { 1444 sal_Bool bOk = sal_True; 1445 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW ); 1446 SCROW nStart = 0, nEnd = 0; 1447 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd ); 1448 while (pPattern && bOk) 1449 { 1450 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() ) 1451 if ( rDestCol.pAttrArray->HasAttrib( nStart, nEnd, HASATTR_PROTECTED ) ) 1452 bOk = sal_False; 1453 1454 pPattern = aAttrIter.Next( nStart, nEnd ); 1455 } 1456 return bOk; 1457 } 1458 1459 1460 void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const 1461 { 1462 ScRange aRange( nCol, 0, nTab ); 1463 1464 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW ); 1465 SCROW nStart = -1, nEnd = -1; 1466 const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd ); 1467 while (pPattern) 1468 { 1469 if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() ) 1470 { 1471 aRange.aStart.SetRow( nStart ); 1472 aRange.aEnd.SetRow( nEnd ); 1473 rDestMark.SetMultiMarkArea( aRange, sal_True ); 1474 } 1475 1476 pPattern = aAttrIter.Next( nStart, nEnd ); 1477 } 1478 } 1479 1480 1481 void ScColumn::SwapCol(ScColumn& rCol) 1482 { 1483 SCSIZE nTemp; 1484 1485 nTemp = rCol.nCount; 1486 rCol.nCount = nCount; 1487 nCount = nTemp; 1488 1489 nTemp = rCol.nLimit; 1490 rCol.nLimit = nLimit; 1491 nLimit = nTemp; 1492 1493 ColEntry* pTempItems = rCol.pItems; 1494 rCol.pItems = pItems; 1495 pItems = pTempItems; 1496 1497 ScAttrArray* pTempAttr = rCol.pAttrArray; 1498 rCol.pAttrArray = pAttrArray; 1499 pAttrArray = pTempAttr; 1500 1501 // #38415# AttrArray muss richtige Spaltennummer haben 1502 pAttrArray->SetCol(nCol); 1503 rCol.pAttrArray->SetCol(rCol.nCol); 1504 1505 SCSIZE i; 1506 if (pItems) 1507 for (i = 0; i < nCount; i++) 1508 { 1509 ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell; 1510 if( pCell->GetCellType() == CELLTYPE_FORMULA) 1511 pCell->aPos.SetCol(nCol); 1512 } 1513 if (rCol.pItems) 1514 for (i = 0; i < rCol.nCount; i++) 1515 { 1516 ScFormulaCell* pCell = (ScFormulaCell*) rCol.pItems[i].pCell; 1517 if( pCell->GetCellType() == CELLTYPE_FORMULA) 1518 pCell->aPos.SetCol(rCol.nCol); 1519 } 1520 } 1521 1522 1523 void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol) 1524 { 1525 pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray); 1526 1527 if (pItems) 1528 { 1529 ::std::vector<SCROW> aRows; 1530 bool bConsecutive = true; 1531 SCSIZE i; 1532 Search( nStartRow, i); // i points to start row or position thereafter 1533 SCSIZE nStartPos = i; 1534 for ( ; i < nCount && pItems[i].nRow <= nEndRow; ++i) 1535 { 1536 SCROW nRow = pItems[i].nRow; 1537 aRows.push_back( nRow); 1538 rCol.Insert( nRow, pItems[i].pCell); 1539 if (nRow != pItems[i].nRow) 1540 { // Listener inserted 1541 bConsecutive = false; 1542 Search( nRow, i); 1543 } 1544 } 1545 SCSIZE nStopPos = i; 1546 if (nStartPos < nStopPos) 1547 { 1548 // Create list of ranges of cell entry positions 1549 typedef ::std::pair<SCSIZE,SCSIZE> PosPair; 1550 typedef ::std::vector<PosPair> EntryPosPairs; 1551 EntryPosPairs aEntries; 1552 if (bConsecutive) 1553 aEntries.push_back( PosPair(nStartPos, nStopPos)); 1554 else 1555 { 1556 bool bFirst = true; 1557 nStopPos = 0; 1558 for (::std::vector<SCROW>::const_iterator it( aRows.begin()); 1559 it != aRows.end() && nStopPos < nCount; ++it, 1560 ++nStopPos) 1561 { 1562 if (!bFirst && *it != pItems[nStopPos].nRow) 1563 { 1564 aEntries.push_back( PosPair(nStartPos, nStopPos)); 1565 bFirst = true; 1566 } 1567 if (bFirst && Search( *it, nStartPos)) 1568 { 1569 bFirst = false; 1570 nStopPos = nStartPos; 1571 } 1572 } 1573 if (!bFirst && nStartPos < nStopPos) 1574 aEntries.push_back( PosPair(nStartPos, nStopPos)); 1575 } 1576 // Broadcast changes 1577 ScAddress aAdr( nCol, 0, nTab ); 1578 ScHint aHint( SC_HINT_DYING, aAdr, NULL ); // areas only 1579 ScAddress& rAddress = aHint.GetAddress(); 1580 ScNoteCell* pNoteCell = new ScNoteCell; // Dummy like in DeleteRange 1581 1582 // #121990# must iterate backwards, because indexes of following cells become invalid 1583 for (EntryPosPairs::reverse_iterator it( aEntries.rbegin()); 1584 it != aEntries.rend(); ++it) 1585 { 1586 nStartPos = (*it).first; 1587 nStopPos = (*it).second; 1588 for (i=nStartPos; i<nStopPos; ++i) 1589 pItems[i].pCell = pNoteCell; 1590 for (i=nStartPos; i<nStopPos; ++i) 1591 { 1592 rAddress.SetRow( pItems[i].nRow ); 1593 pDocument->AreaBroadcast( aHint ); 1594 } 1595 nCount -= nStopPos - nStartPos; 1596 memmove( &pItems[nStartPos], &pItems[nStopPos], 1597 (nCount - nStartPos) * sizeof(ColEntry) ); 1598 } 1599 delete pNoteCell; 1600 pItems[nCount].nRow = 0; 1601 pItems[nCount].pCell = NULL; 1602 } 1603 } 1604 } 1605 1606 1607 void ScColumn::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1, 1608 SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz, 1609 ScDocument* pUndoDoc ) 1610 { 1611 if (pItems) 1612 { 1613 ScRange aRange( ScAddress( nCol1, nRow1, nTab1 ), 1614 ScAddress( nCol2, nRow2, nTab2 ) ); 1615 if ( eUpdateRefMode == URM_COPY && nRow1 == nRow2 ) 1616 { // z.B. eine einzelne Zelle aus dem Clipboard eingefuegt 1617 SCSIZE nIndex; 1618 if ( Search( nRow1, nIndex ) ) 1619 { 1620 ScFormulaCell* pCell = (ScFormulaCell*) pItems[nIndex].pCell; 1621 if( pCell->GetCellType() == CELLTYPE_FORMULA) 1622 pCell->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc ); 1623 } 1624 } 1625 else 1626 { 1627 // #90279# For performance reasons two loop bodies instead of 1628 // testing for update mode in each iteration. 1629 // Anyways, this is still a bottleneck on large arrays with few 1630 // formulas cells. 1631 if ( eUpdateRefMode == URM_COPY ) 1632 { 1633 SCSIZE i; 1634 Search( nRow1, i ); 1635 for ( ; i < nCount; i++ ) 1636 { 1637 SCROW nRow = pItems[i].nRow; 1638 if ( nRow > nRow2 ) 1639 break; 1640 ScBaseCell* pCell = pItems[i].pCell; 1641 if( pCell->GetCellType() == CELLTYPE_FORMULA) 1642 { 1643 ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc ); 1644 if ( nRow != pItems[i].nRow ) 1645 Search( nRow, i ); // Listener removed/inserted? 1646 } 1647 } 1648 } 1649 else 1650 { 1651 SCSIZE i = 0; 1652 for ( ; i < nCount; i++ ) 1653 { 1654 ScBaseCell* pCell = pItems[i].pCell; 1655 if( pCell->GetCellType() == CELLTYPE_FORMULA) 1656 { 1657 SCROW nRow = pItems[i].nRow; 1658 // When deleting rows on several sheets, the formula's position may be updated with the first call, 1659 // so the undo position must be passed from here. 1660 ScAddress aUndoPos( nCol, nRow, nTab ); 1661 ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc, &aUndoPos ); 1662 if ( nRow != pItems[i].nRow ) 1663 Search( nRow, i ); // Listener removed/inserted? 1664 } 1665 } 1666 } 1667 } 1668 } 1669 } 1670 1671 1672 void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest, 1673 ScDocument* pUndoDoc ) 1674 { 1675 if (pItems) 1676 for (SCSIZE i=0; i<nCount; i++) 1677 { 1678 ScBaseCell* pCell = pItems[i].pCell; 1679 if (pCell->GetCellType() == CELLTYPE_FORMULA) 1680 { 1681 SCROW nRow = pItems[i].nRow; 1682 ((ScFormulaCell*)pCell)->UpdateTranspose( rSource, rDest, pUndoDoc ); 1683 if ( nRow != pItems[i].nRow ) 1684 Search( nRow, i ); // Listener geloescht/eingefuegt? 1685 } 1686 } 1687 } 1688 1689 1690 void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ) 1691 { 1692 if (pItems) 1693 for (SCSIZE i=0; i<nCount; i++) 1694 { 1695 ScBaseCell* pCell = pItems[i].pCell; 1696 if (pCell->GetCellType() == CELLTYPE_FORMULA) 1697 { 1698 SCROW nRow = pItems[i].nRow; 1699 ((ScFormulaCell*)pCell)->UpdateGrow( rArea, nGrowX, nGrowY ); 1700 if ( nRow != pItems[i].nRow ) 1701 Search( nRow, i ); // Listener geloescht/eingefuegt? 1702 } 1703 } 1704 } 1705 1706 1707 void ScColumn::UpdateInsertTab( SCTAB nTable) 1708 { 1709 if (nTab >= nTable) 1710 pAttrArray->SetTab(++nTab); 1711 if( pItems ) 1712 UpdateInsertTabOnlyCells( nTable ); 1713 } 1714 1715 1716 void ScColumn::UpdateInsertTabOnlyCells( SCTAB nTable) 1717 { 1718 if (pItems) 1719 for (SCSIZE i = 0; i < nCount; i++) 1720 { 1721 ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell; 1722 if( pCell->GetCellType() == CELLTYPE_FORMULA) 1723 { 1724 SCROW nRow = pItems[i].nRow; 1725 pCell->UpdateInsertTab(nTable); 1726 if ( nRow != pItems[i].nRow ) 1727 Search( nRow, i ); // Listener geloescht/eingefuegt? 1728 } 1729 } 1730 } 1731 1732 1733 void ScColumn::UpdateInsertTabAbs(SCTAB nTable) 1734 { 1735 if (pItems) 1736 for (SCSIZE i = 0; i < nCount; i++) 1737 { 1738 ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell; 1739 if( pCell->GetCellType() == CELLTYPE_FORMULA) 1740 { 1741 SCROW nRow = pItems[i].nRow; 1742 pCell->UpdateInsertTabAbs(nTable); 1743 if ( nRow != pItems[i].nRow ) 1744 Search( nRow, i ); // Listener geloescht/eingefuegt? 1745 } 1746 } 1747 } 1748 1749 1750 void ScColumn::UpdateDeleteTab( SCTAB nTable, sal_Bool bIsMove, ScColumn* pRefUndo ) 1751 { 1752 if (nTab > nTable) 1753 pAttrArray->SetTab(--nTab); 1754 1755 if (pItems) 1756 for (SCSIZE i = 0; i < nCount; i++) 1757 if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA ) 1758 { 1759 SCROW nRow = pItems[i].nRow; 1760 ScFormulaCell* pOld = (ScFormulaCell*)pItems[i].pCell; 1761 1762 /* Do not copy cell note to the undo document. Undo will copy 1763 back the formula cell while keeping the original note. */ 1764 ScBaseCell* pSave = pRefUndo ? pOld->CloneWithoutNote( *pDocument ) : 0; 1765 1766 sal_Bool bChanged = pOld->UpdateDeleteTab(nTable, bIsMove); 1767 if ( nRow != pItems[i].nRow ) 1768 Search( nRow, i ); // Listener geloescht/eingefuegt? 1769 1770 if (pRefUndo) 1771 { 1772 if (bChanged) 1773 pRefUndo->Insert( nRow, pSave ); 1774 else if(pSave) 1775 pSave->Delete(); 1776 } 1777 } 1778 } 1779 1780 1781 void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo ) 1782 { 1783 nTab = nTabNo; 1784 pAttrArray->SetTab( nTabNo ); 1785 if (pItems) 1786 for (SCSIZE i = 0; i < nCount; i++) 1787 { 1788 ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell; 1789 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 1790 { 1791 SCROW nRow = pItems[i].nRow; 1792 pCell->UpdateMoveTab( nOldPos, nNewPos, nTabNo ); 1793 if ( nRow != pItems[i].nRow ) 1794 Search( nRow, i ); // Listener geloescht/eingefuegt? 1795 } 1796 } 1797 } 1798 1799 1800 void ScColumn::UpdateCompile( sal_Bool bForceIfNameInUse ) 1801 { 1802 if (pItems) 1803 for (SCSIZE i = 0; i < nCount; i++) 1804 { 1805 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell; 1806 if( p->GetCellType() == CELLTYPE_FORMULA ) 1807 { 1808 SCROW nRow = pItems[i].nRow; 1809 p->UpdateCompile( bForceIfNameInUse ); 1810 if ( nRow != pItems[i].nRow ) 1811 Search( nRow, i ); // Listener geloescht/eingefuegt? 1812 } 1813 } 1814 } 1815 1816 1817 void ScColumn::SetTabNo(SCTAB nNewTab) 1818 { 1819 nTab = nNewTab; 1820 pAttrArray->SetTab( nNewTab ); 1821 if (pItems) 1822 for (SCSIZE i = 0; i < nCount; i++) 1823 { 1824 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell; 1825 if( p->GetCellType() == CELLTYPE_FORMULA ) 1826 p->aPos.SetTab( nNewTab ); 1827 } 1828 } 1829 1830 1831 sal_Bool ScColumn::IsRangeNameInUse(SCROW nRow1, SCROW nRow2, sal_uInt16 nIndex) const 1832 { 1833 sal_Bool bInUse = sal_False; 1834 if (pItems) 1835 for (SCSIZE i = 0; !bInUse && (i < nCount); i++) 1836 if ((pItems[i].nRow >= nRow1) && 1837 (pItems[i].nRow <= nRow2) && 1838 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA)) 1839 bInUse = ((ScFormulaCell*)pItems[i].pCell)->IsRangeNameInUse(nIndex); 1840 return bInUse; 1841 } 1842 1843 void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<sal_uInt16>& rIndexes) const 1844 { 1845 if (pItems) 1846 for (SCSIZE i = 0; i < nCount; i++) 1847 if ((pItems[i].nRow >= nRow1) && 1848 (pItems[i].nRow <= nRow2) && 1849 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA)) 1850 ((ScFormulaCell*)pItems[i].pCell)->FindRangeNamesInUse(rIndexes); 1851 } 1852 1853 void ScColumn::ReplaceRangeNamesInUse(SCROW nRow1, SCROW nRow2, 1854 const ScRangeData::IndexMap& rMap ) 1855 { 1856 if (pItems) 1857 for (SCSIZE i = 0; i < nCount; i++) 1858 { 1859 if ((pItems[i].nRow >= nRow1) && 1860 (pItems[i].nRow <= nRow2) && 1861 (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA)) 1862 { 1863 SCROW nRow = pItems[i].nRow; 1864 ((ScFormulaCell*)pItems[i].pCell)->ReplaceRangeNamesInUse( rMap ); 1865 if ( nRow != pItems[i].nRow ) 1866 Search( nRow, i ); // Listener geloescht/eingefuegt? 1867 } 1868 } 1869 } 1870 1871 void ScColumn::SetDirtyVar() 1872 { 1873 for (SCSIZE i=0; i<nCount; i++) 1874 { 1875 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell; 1876 if( p->GetCellType() == CELLTYPE_FORMULA ) 1877 p->SetDirtyVar(); 1878 } 1879 } 1880 1881 1882 void ScColumn::SetDirty() 1883 { 1884 // wird nur dokumentweit verwendet, kein FormulaTrack 1885 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc(); 1886 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden 1887 for (SCSIZE i=0; i<nCount; i++) 1888 { 1889 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell; 1890 if( p->GetCellType() == CELLTYPE_FORMULA ) 1891 { 1892 p->SetDirtyVar(); 1893 if ( !pDocument->IsInFormulaTree( p ) ) 1894 pDocument->PutInFormulaTree( p ); 1895 } 1896 } 1897 pDocument->SetAutoCalc( bOldAutoCalc ); 1898 } 1899 1900 1901 void ScColumn::SetDirty( const ScRange& rRange ) 1902 { // broadcastet alles innerhalb eines Range, mit FormulaTrack 1903 if ( !pItems || !nCount ) 1904 return ; 1905 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc(); 1906 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden 1907 SCROW nRow2 = rRange.aEnd.Row(); 1908 ScAddress aPos( nCol, 0, nTab ); 1909 ScHint aHint( SC_HINT_DATACHANGED, aPos, NULL ); 1910 SCROW nRow; 1911 SCSIZE nIndex; 1912 Search( rRange.aStart.Row(), nIndex ); 1913 while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 ) 1914 { 1915 ScBaseCell* pCell = pItems[nIndex].pCell; 1916 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 1917 ((ScFormulaCell*)pCell)->SetDirty(); 1918 else 1919 { 1920 aHint.GetAddress().SetRow( nRow ); 1921 aHint.SetCell( pCell ); 1922 pDocument->Broadcast( aHint ); 1923 } 1924 nIndex++; 1925 } 1926 pDocument->SetAutoCalc( bOldAutoCalc ); 1927 } 1928 1929 1930 void ScColumn::SetTableOpDirty( const ScRange& rRange ) 1931 { 1932 if ( !pItems || !nCount ) 1933 return ; 1934 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc(); 1935 pDocument->SetAutoCalc( sal_False ); // no multiple recalculation 1936 SCROW nRow2 = rRange.aEnd.Row(); 1937 ScAddress aPos( nCol, 0, nTab ); 1938 ScHint aHint( SC_HINT_TABLEOPDIRTY, aPos, NULL ); 1939 SCROW nRow; 1940 SCSIZE nIndex; 1941 Search( rRange.aStart.Row(), nIndex ); 1942 while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 ) 1943 { 1944 ScBaseCell* pCell = pItems[nIndex].pCell; 1945 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 1946 ((ScFormulaCell*)pCell)->SetTableOpDirty(); 1947 else 1948 { 1949 aHint.GetAddress().SetRow( nRow ); 1950 aHint.SetCell( pCell ); 1951 pDocument->Broadcast( aHint ); 1952 } 1953 nIndex++; 1954 } 1955 pDocument->SetAutoCalc( bOldAutoCalc ); 1956 } 1957 1958 1959 void ScColumn::SetDirtyAfterLoad() 1960 { 1961 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc(); 1962 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden 1963 for (SCSIZE i=0; i<nCount; i++) 1964 { 1965 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell; 1966 #if 1 1967 // Simply set dirty and append to FormulaTree, without broadcasting, 1968 // which is a magnitude faster. This is used to calculate the entire 1969 // document, e.g. when loading alien file formats. 1970 if ( p->GetCellType() == CELLTYPE_FORMULA ) 1971 p->SetDirtyAfterLoad(); 1972 #else 1973 /* This was used with the binary file format that stored results, where only 1974 * newly compiled and volatile functions and their dependents had to be 1975 * recalculated, which was faster then. Since that was moved to 'binfilter' to 1976 * convert to an XML file this isn't needed anymore, and not used for other 1977 * file formats. Kept for reference in case mechanism needs to be reactivated 1978 * for some file formats, we'd have to introduce a controlling parameter to 1979 * this method here then. 1980 */ 1981 1982 // If the cell was alsready dirty because of CalcAfterLoad, 1983 // FormulaTracking has to take place. 1984 if ( p->GetCellType() == CELLTYPE_FORMULA && p->GetDirty() ) 1985 p->SetDirty(); 1986 #endif 1987 } 1988 pDocument->SetAutoCalc( bOldAutoCalc ); 1989 } 1990 1991 1992 void ScColumn::SetRelNameDirty() 1993 { 1994 sal_Bool bOldAutoCalc = pDocument->GetAutoCalc(); 1995 pDocument->SetAutoCalc( sal_False ); // Mehrfachberechnungen vermeiden 1996 for (SCSIZE i=0; i<nCount; i++) 1997 { 1998 ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell; 1999 if( p->GetCellType() == CELLTYPE_FORMULA && p->HasRelNameReference() ) 2000 p->SetDirty(); 2001 } 2002 pDocument->SetAutoCalc( bOldAutoCalc ); 2003 } 2004 2005 2006 void ScColumn::CalcAll() 2007 { 2008 if (pItems) 2009 for (SCSIZE i=0; i<nCount; i++) 2010 { 2011 ScBaseCell* pCell = pItems[i].pCell; 2012 if (pCell->GetCellType() == CELLTYPE_FORMULA) 2013 { 2014 #if OSL_DEBUG_LEVEL > 1 2015 // nach F9 ctrl-F9: ueberprueft die Berechnung per FormulaTree 2016 ScFormulaCell* pFCell = (ScFormulaCell*)pCell; 2017 double nOldVal, nNewVal; 2018 nOldVal = pFCell->GetValue(); 2019 #endif 2020 ((ScFormulaCell*)pCell)->Interpret(); 2021 #if OSL_DEBUG_LEVEL > 1 2022 if ( pFCell->GetCode()->IsRecalcModeNormal() ) 2023 nNewVal = pFCell->GetValue(); 2024 else 2025 nNewVal = nOldVal; // random(), jetzt() etc. 2026 DBG_ASSERT( nOldVal==nNewVal, "CalcAll: nOldVal != nNewVal" ); 2027 #endif 2028 } 2029 } 2030 } 2031 2032 2033 void ScColumn::CompileAll() 2034 { 2035 if (pItems) 2036 for (SCSIZE i = 0; i < nCount; i++) 2037 { 2038 ScBaseCell* pCell = pItems[i].pCell; 2039 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 2040 { 2041 SCROW nRow = pItems[i].nRow; 2042 // fuer unbedingtes kompilieren 2043 // bCompile=sal_True und pCode->nError=0 2044 ((ScFormulaCell*)pCell)->GetCode()->SetCodeError( 0 ); 2045 ((ScFormulaCell*)pCell)->SetCompile( sal_True ); 2046 ((ScFormulaCell*)pCell)->CompileTokenArray(); 2047 if ( nRow != pItems[i].nRow ) 2048 Search( nRow, i ); // Listener geloescht/eingefuegt? 2049 } 2050 } 2051 } 2052 2053 2054 void ScColumn::CompileXML( ScProgress& rProgress ) 2055 { 2056 if (pItems) 2057 for (SCSIZE i = 0; i < nCount; i++) 2058 { 2059 ScBaseCell* pCell = pItems[i].pCell; 2060 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 2061 { 2062 SCROW nRow = pItems[i].nRow; 2063 ((ScFormulaCell*)pCell)->CompileXML( rProgress ); 2064 if ( nRow != pItems[i].nRow ) 2065 Search( nRow, i ); // Listener geloescht/eingefuegt? 2066 } 2067 } 2068 } 2069 2070 2071 void ScColumn::CalcAfterLoad() 2072 { 2073 if (pItems) 2074 for (SCSIZE i = 0; i < nCount; i++) 2075 { 2076 ScBaseCell* pCell = pItems[i].pCell; 2077 if ( pCell->GetCellType() == CELLTYPE_FORMULA ) 2078 ((ScFormulaCell*)pCell)->CalcAfterLoad(); 2079 } 2080 } 2081 2082 2083 void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow ) 2084 { 2085 if (pItems) 2086 { 2087 SCSIZE nIndex; 2088 Search(nStartRow,nIndex); 2089 while (nIndex<nCount && pItems[nIndex].nRow <= nEndRow) 2090 { 2091 ScBaseCell* pCell = pItems[nIndex].pCell; 2092 if (pCell->GetCellType() == CELLTYPE_FORMULA) 2093 ((ScFormulaCell*)pCell)->ResetChanged(); 2094 ++nIndex; 2095 } 2096 } 2097 } 2098 2099 2100 sal_Bool ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst) const 2101 { 2102 // used in GetOptimalHeight - ambiguous script type counts as edit cell 2103 2104 SCROW nRow = 0; 2105 SCSIZE nIndex; 2106 Search(nStartRow,nIndex); 2107 while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : sal_False ) 2108 { 2109 ScBaseCell* pCell = pItems[nIndex].pCell; 2110 CellType eCellType = pCell->GetCellType(); 2111 if ( eCellType == CELLTYPE_EDIT || 2112 IsAmbiguousScriptNonZero( pDocument->GetScriptType(nCol, nRow, nTab, pCell) ) || 2113 ((eCellType == CELLTYPE_FORMULA) && ((ScFormulaCell*)pCell)->IsMultilineResult()) ) 2114 { 2115 rFirst = nRow; 2116 return sal_True; 2117 } 2118 ++nIndex; 2119 } 2120 2121 return sal_False; 2122 } 2123 2124 2125 SCsROW ScColumn::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle, 2126 sal_Bool bUp, sal_Bool bInSelection, const ScMarkData& rMark ) 2127 { 2128 if (bInSelection) 2129 { 2130 if (rMark.IsMultiMarked()) 2131 return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp, 2132 (ScMarkArray*) rMark.GetArray()+nCol ); //! const 2133 else 2134 return -1; 2135 } 2136 else 2137 return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp, NULL ); 2138 } 2139 2140 2141 sal_Bool ScColumn::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle, 2142 sal_Bool bUp, sal_Bool bInSelection, const ScMarkData& rMark ) 2143 { 2144 if (bInSelection) 2145 { 2146 if (rMark.IsMultiMarked()) 2147 return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, 2148 (ScMarkArray*) rMark.GetArray()+nCol ); //! const 2149 else 2150 return sal_False; 2151 } 2152 else 2153 return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, NULL ); 2154 } 2155 2156 2157