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