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 //------------------------------------------------------------------------ 30 31 #include "scitems.hxx" 32 #include <svx/algitem.hxx> 33 #include <editeng/boxitem.hxx> 34 #include <editeng/bolnitem.hxx> 35 #include <editeng/frmdiritem.hxx> 36 #include <editeng/shaditem.hxx> 37 #include <svl/poolcach.hxx> 38 #include <editeng/fontitem.hxx> 39 #include <unotools/fontcvt.hxx> 40 41 #include "attarray.hxx" 42 #include "global.hxx" 43 #include "document.hxx" 44 #include "docpool.hxx" 45 #include "patattr.hxx" 46 #include "stlsheet.hxx" 47 #include "stlpool.hxx" 48 #include "markarr.hxx" 49 #include "rechead.hxx" 50 #include "globstr.hrc" 51 #include "segmenttree.hxx" 52 53 #undef DBG_INVALIDATE 54 #define DBGOUTPUT(s) \ 55 DBG_ERROR( String("Invalidate ") + String(s) + String(": ") \ 56 + String(nCol) + String('/') + String(aAdrStart.Row()) + String('/') + String(nTab) \ 57 + String(" bis ") \ 58 + String(nCol) + String('/') + String(aAdrEnd.Row()) + String('/') + String(nTab) \ 59 ); 60 61 // STATIC DATA ----------------------------------------------------------- 62 63 64 //------------------------------------------------------------------------ 65 66 ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) : 67 nCol( nNewCol ), 68 nTab( nNewTab ), 69 pDocument( pDoc ) 70 { 71 nCount = nLimit = 1; 72 pData = new ScAttrEntry[1]; 73 if (pData) 74 { 75 pData[0].nRow = MAXROW; 76 pData[0].pPattern = pDocument->GetDefPattern(); // ohne Put !!! 77 } 78 } 79 80 //------------------------------------------------------------------------ 81 82 ScAttrArray::~ScAttrArray() 83 { 84 #ifdef DBG_UTIL 85 TestData(); 86 #endif 87 88 if (pData) 89 { 90 ScDocumentPool* pDocPool = pDocument->GetPool(); 91 for (SCSIZE i=0; i<nCount; i++) 92 pDocPool->Remove(*pData[i].pPattern); 93 94 delete[] pData; 95 } 96 } 97 98 //------------------------------------------------------------------------ 99 #ifdef DBG_UTIL 100 void ScAttrArray::TestData() const 101 { 102 103 sal_uInt16 nErr = 0; 104 if (pData) 105 { 106 SCSIZE nPos; 107 for (nPos=0; nPos<nCount; nPos++) 108 { 109 if (nPos > 0) 110 if (pData[nPos].pPattern == pData[nPos-1].pPattern || pData[nPos].nRow <= pData[nPos-1].nRow) 111 ++nErr; 112 if (pData[nPos].pPattern->Which() != ATTR_PATTERN) 113 ++nErr; 114 } 115 if ( nPos && pData[nPos-1].nRow != MAXROW ) 116 ++nErr; 117 } 118 if (nErr) 119 { 120 ByteString aMsg = ByteString::CreateFromInt32(nErr); 121 aMsg += " errors in attribute array, column "; 122 aMsg += ByteString::CreateFromInt32(nCol); 123 DBG_ERROR( aMsg.GetBuffer() ); 124 } 125 } 126 #endif 127 128 //------------------------------------------------------------------------ 129 130 void ScAttrArray::Reset( const ScPatternAttr* pPattern, sal_Bool bAlloc ) 131 { 132 if (pData) 133 { 134 ScDocumentPool* pDocPool = pDocument->GetPool(); 135 const ScPatternAttr* pOldPattern; 136 ScAddress aAdrStart( nCol, 0, nTab ); 137 ScAddress aAdrEnd ( nCol, 0, nTab ); 138 139 for (SCSIZE i=0; i<nCount; i++) 140 { 141 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert 142 pOldPattern = pData[i].pPattern; 143 sal_Bool bNumFormatChanged; 144 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, 145 pPattern->GetItemSet(), pOldPattern->GetItemSet() ) ) 146 { 147 aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 ); 148 aAdrEnd .SetRow( pData[i].nRow ); 149 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); 150 #ifdef DBG_INVALIDATE 151 DBGOUTPUT("Reset"); 152 #endif 153 } 154 // bedingtes Format gesetzt oder geloescht? 155 if ( &pPattern->GetItem(ATTR_CONDITIONAL) != &pOldPattern->GetItem(ATTR_CONDITIONAL) ) 156 { 157 pDocument->ConditionalChanged( ((const SfxUInt32Item&) 158 pOldPattern->GetItem(ATTR_CONDITIONAL)).GetValue() ); 159 pDocument->ConditionalChanged( ((const SfxUInt32Item&) 160 pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() ); 161 } 162 pDocPool->Remove(*pOldPattern); 163 } 164 delete[] pData; 165 166 if (pDocument->IsStreamValid(nTab)) 167 pDocument->SetStreamValid(nTab, sal_False); 168 169 if (bAlloc) 170 { 171 nCount = nLimit = 1; 172 pData = new ScAttrEntry[1]; 173 if (pData) 174 { 175 ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern); 176 pData[0].nRow = MAXROW; 177 pData[0].pPattern = pNewPattern; 178 } 179 } 180 else 181 { 182 nCount = nLimit = 0; 183 pData = NULL; // muss sofort wieder belegt werden ! 184 } 185 } 186 } 187 188 189 sal_Bool ScAttrArray::Concat(SCSIZE nPos) 190 { 191 sal_Bool bRet = sal_False; 192 if (pData && (nPos < nCount)) 193 { 194 if (nPos > 0) 195 { 196 if (pData[nPos - 1].pPattern == pData[nPos].pPattern) 197 { 198 pData[nPos - 1].nRow = pData[nPos].nRow; 199 pDocument->GetPool()->Remove(*pData[nPos].pPattern); 200 memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry)); 201 pData[nCount - 1].pPattern = NULL; 202 pData[nCount - 1].nRow = 0; 203 nCount--; 204 nPos--; 205 bRet = sal_True; 206 } 207 } 208 if (nPos + 1 < nCount) 209 { 210 if (pData[nPos + 1].pPattern == pData[nPos].pPattern) 211 { 212 pData[nPos].nRow = pData[nPos + 1].nRow; 213 pDocument->GetPool()->Remove(*pData[nPos].pPattern); 214 memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry)); 215 pData[nCount - 1].pPattern = NULL; 216 pData[nCount - 1].nRow = 0; 217 nCount--; 218 bRet = sal_True; 219 } 220 } 221 } 222 return bRet; 223 } 224 225 //------------------------------------------------------------------------ 226 227 sal_Bool ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const 228 { 229 long nLo = 0; 230 long nHi = static_cast<long>(nCount) - 1; 231 long nStartRow = 0; 232 long nEndRow = 0; 233 long i = 0; 234 sal_Bool bFound = (nCount == 1); 235 if (pData) 236 { 237 while ( !bFound && nLo <= nHi ) 238 { 239 i = (nLo + nHi) / 2; 240 if (i > 0) 241 nStartRow = (long) pData[i - 1].nRow; 242 else 243 nStartRow = -1; 244 nEndRow = (long) pData[i].nRow; 245 if (nEndRow < (long) nRow) 246 nLo = ++i; 247 else 248 if (nStartRow >= (long) nRow) 249 nHi = --i; 250 else 251 bFound = sal_True; 252 } 253 } 254 else 255 bFound = sal_False; 256 257 if (bFound) 258 nIndex=(SCSIZE)i; 259 else 260 nIndex=0; 261 return bFound; 262 } 263 264 265 const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const 266 { 267 SCSIZE i; 268 if (Search( nRow, i )) 269 return pData[i].pPattern; 270 else 271 return NULL; 272 } 273 274 275 const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow, 276 SCROW& rEndRow, SCROW nRow ) const 277 { 278 SCSIZE nIndex; 279 if ( Search( nRow, nIndex ) ) 280 { 281 if ( nIndex > 0 ) 282 rStartRow = pData[nIndex-1].nRow + 1; 283 else 284 rStartRow = 0; 285 rEndRow = pData[nIndex].nRow; 286 return pData[nIndex].pPattern; 287 } 288 return NULL; 289 } 290 291 //------------------------------------------------------------------------ 292 293 void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, sal_Bool bPutToPool ) 294 { 295 SetPatternArea( nRow, nRow, pPattern, bPutToPool ); 296 } 297 298 bool ScAttrArray::Reserve( SCSIZE nReserve ) 299 { 300 if ( nCount <= nReserve ) 301 { 302 if( ScAttrEntry* pNewData = new (std::nothrow) ScAttrEntry[nReserve] ) 303 { 304 nLimit = nReserve; 305 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) ); 306 delete[] pData; 307 pData = pNewData; 308 return true; 309 } 310 else 311 return false; 312 } 313 else 314 return false; 315 } 316 317 void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern, sal_Bool bPutToPool ) 318 { 319 if (ValidRow(nStartRow) && ValidRow(nEndRow)) 320 { 321 if (bPutToPool) 322 pPattern = (const ScPatternAttr*) &pDocument->GetPool()->Put(*pPattern); 323 324 if ((nStartRow == 0) && (nEndRow == MAXROW)) 325 Reset(pPattern); 326 else 327 { 328 SCSIZE nNeeded = nCount + 2; 329 if ( nLimit < nNeeded ) 330 { 331 nLimit += SC_ATTRARRAY_DELTA; 332 if ( nLimit < nNeeded ) 333 nLimit = nNeeded; 334 ScAttrEntry* pNewData = new ScAttrEntry[nLimit]; 335 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) ); 336 delete[] pData; 337 pData = pNewData; 338 } 339 340 ScAddress aAdrStart( nCol, 0, nTab ); 341 ScAddress aAdrEnd ( nCol, 0, nTab ); 342 343 SCSIZE ni = 0; // number of entries in beginning 344 SCSIZE nx = 0; // track position 345 SCROW ns = 0; // start row of track position 346 if ( nStartRow > 0 ) 347 { 348 // skip beginning 349 SCSIZE nIndex; 350 Search( nStartRow, nIndex ); 351 ni = nIndex; 352 353 if ( ni > 0 ) 354 { 355 nx = ni; 356 ns = pData[ni-1].nRow+1; 357 } 358 } 359 360 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert 361 // oder bedingte Formate neu gesetzt oder geloescht werden 362 while ( ns <= nEndRow ) 363 { 364 const SfxItemSet& rNewSet = pPattern->GetItemSet(); 365 const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet(); 366 367 sal_Bool bNumFormatChanged; 368 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, 369 rNewSet, rOldSet ) ) 370 { 371 aAdrStart.SetRow( Max(nStartRow,ns) ); 372 aAdrEnd .SetRow( Min(nEndRow,pData[nx].nRow) ); 373 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); 374 #ifdef DBG_INVALIDATE 375 DBGOUTPUT("SetPatternArea"); 376 #endif 377 } 378 if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) ) 379 { 380 pDocument->ConditionalChanged( ((const SfxUInt32Item&) 381 rOldSet.Get(ATTR_CONDITIONAL)).GetValue() ); 382 pDocument->ConditionalChanged( ((const SfxUInt32Item&) 383 rNewSet.Get(ATTR_CONDITIONAL)).GetValue() ); 384 } 385 ns = pData[nx].nRow + 1; 386 nx++; 387 } 388 389 // continue modifying data array 390 391 SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert) 392 sal_Bool bCombined = sal_False; 393 sal_Bool bSplit = sal_False; 394 if ( nStartRow > 0 ) 395 { 396 nInsert = MAXROWCOUNT; 397 if ( pData[ni].pPattern != pPattern ) 398 { 399 if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) ) 400 { // may be a split or a simple insert or just a shrink, 401 // row adjustment is done further down 402 if ( pData[ni].nRow > nEndRow ) 403 bSplit = sal_True; 404 ni++; 405 nInsert = ni; 406 } 407 else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 ) 408 nInsert = ni; 409 } 410 if ( ni > 0 && pData[ni-1].pPattern == pPattern ) 411 { // combine 412 pData[ni-1].nRow = nEndRow; 413 nInsert = MAXROWCOUNT; 414 bCombined = sal_True; 415 } 416 } 417 else 418 nInsert = 0; 419 420 SCSIZE nj = ni; // stop position of range to replace 421 while ( nj < nCount && pData[nj].nRow <= nEndRow ) 422 nj++; 423 if ( !bSplit ) 424 { 425 if ( nj < nCount && pData[nj].pPattern == pPattern ) 426 { // combine 427 if ( ni > 0 ) 428 { 429 if ( pData[ni-1].pPattern == pPattern ) 430 { // adjacent entries 431 pData[ni-1].nRow = pData[nj].nRow; 432 nj++; 433 } 434 else if ( ni == nInsert ) 435 pData[ni-1].nRow = nStartRow - 1; // shrink 436 } 437 nInsert = MAXROWCOUNT; 438 bCombined = sal_True; 439 } 440 else if ( ni > 0 && ni == nInsert ) 441 pData[ni-1].nRow = nStartRow - 1; // shrink 442 } 443 ScDocumentPool* pDocPool = pDocument->GetPool(); 444 if ( bSplit ) 445 { // duplicate splitted entry in pool 446 pDocPool->Put( *pData[ni-1].pPattern ); 447 } 448 if ( ni < nj ) 449 { // remove middle entries 450 for ( SCSIZE nk=ni; nk<nj; nk++) 451 { // remove entries from pool 452 pDocPool->Remove( *pData[nk].pPattern ); 453 } 454 if ( !bCombined ) 455 { // replace one entry 456 pData[ni].nRow = nEndRow; 457 pData[ni].pPattern = pPattern; 458 ni++; 459 nInsert = MAXROWCOUNT; 460 } 461 if ( ni < nj ) 462 { // remove entries 463 memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) ); 464 nCount -= nj - ni; 465 } 466 } 467 468 if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) ) 469 { // insert or append new entry 470 if ( nInsert <= nCount ) 471 { 472 if ( !bSplit ) 473 memmove( pData + nInsert + 1, pData + nInsert, 474 (nCount - nInsert) * sizeof(ScAttrEntry) ); 475 else 476 { 477 memmove( pData + nInsert + 2, pData + nInsert, 478 (nCount - nInsert) * sizeof(ScAttrEntry) ); 479 pData[nInsert+1] = pData[nInsert-1]; 480 nCount++; 481 } 482 } 483 if ( nInsert ) 484 pData[nInsert-1].nRow = nStartRow - 1; 485 pData[nInsert].nRow = nEndRow; 486 pData[nInsert].pPattern = pPattern; 487 nCount++; 488 } 489 490 if (pDocument->IsStreamValid(nTab)) 491 pDocument->SetStreamValid(nTab, sal_False); 492 } 493 } 494 // InfoBox(0, String(nCount) + String(" Eintraege") ).Execute(); 495 496 #ifdef DBG_UTIL 497 TestData(); 498 #endif 499 } 500 501 502 void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle ) 503 { 504 if (ValidRow(nStartRow) && ValidRow(nEndRow)) 505 { 506 SCSIZE nPos; 507 SCROW nStart=0; 508 if (!Search( nStartRow, nPos )) 509 { 510 DBG_ERROR("Search-Fehler"); 511 return; 512 } 513 514 ScAddress aAdrStart( nCol, 0, nTab ); 515 ScAddress aAdrEnd ( nCol, 0, nTab ); 516 517 do 518 { 519 const ScPatternAttr* pOldPattern = pData[nPos].pPattern; 520 ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern); 521 pNewPattern->SetStyleSheet(pStyle); 522 SCROW nY1 = nStart; 523 SCROW nY2 = pData[nPos].nRow; 524 nStart = pData[nPos].nRow + 1; 525 526 if ( *pNewPattern == *pOldPattern ) 527 { 528 // keep the original pattern (might be default) 529 // pNewPattern is deleted below 530 nPos++; 531 } 532 else if ( nY1 < nStartRow || nY2 > nEndRow ) 533 { 534 if (nY1 < nStartRow) nY1=nStartRow; 535 if (nY2 > nEndRow) nY2=nEndRow; 536 SetPatternArea( nY1, nY2, pNewPattern, sal_True ); 537 Search( nStart, nPos ); 538 } 539 else 540 { 541 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert 542 // bedingte Formate in Vorlagen gibt es (noch) nicht 543 544 const SfxItemSet& rNewSet = pNewPattern->GetItemSet(); 545 const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); 546 547 sal_Bool bNumFormatChanged; 548 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, 549 rNewSet, rOldSet ) ) 550 { 551 aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 ); 552 aAdrEnd .SetRow( pData[nPos].nRow ); 553 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); 554 #ifdef DBG_INVALIDATE 555 DBGOUTPUT("ApplyStyleArea"); 556 #endif 557 } 558 559 pDocument->GetPool()->Remove(*pData[nPos].pPattern); 560 pData[nPos].pPattern = (const ScPatternAttr*) 561 &pDocument->GetPool()->Put(*pNewPattern); 562 if (Concat(nPos)) 563 Search(nStart, nPos); 564 else 565 nPos++; 566 } 567 delete pNewPattern; 568 } 569 while ((nStart <= nEndRow) && (nPos < nCount)); 570 571 if (pDocument->IsStreamValid(nTab)) 572 pDocument->SetStreamValid(nTab, sal_False); 573 } 574 575 #ifdef DBG_UTIL 576 TestData(); 577 #endif 578 } 579 580 581 // const wird weggecastet, weil es sonst 582 // zu ineffizient/kompliziert wird! 583 #define SET_LINECOLOR(dest,c) \ 584 if ((dest)) \ 585 { \ 586 ((SvxBorderLine*)(dest))->SetColor((c)); \ 587 } 588 589 #define SET_LINE(dest,src) \ 590 if ((dest)) \ 591 { \ 592 SvxBorderLine* pCast = (SvxBorderLine*)(dest); \ 593 pCast->SetOutWidth((src)->GetOutWidth()); \ 594 pCast->SetInWidth ((src)->GetInWidth()); \ 595 pCast->SetDistance((src)->GetDistance()); \ 596 } 597 598 void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow, 599 const SvxBorderLine* pLine, sal_Bool bColorOnly ) 600 { 601 if ( bColorOnly && !pLine ) 602 return; 603 604 if (ValidRow(nStartRow) && ValidRow(nEndRow)) 605 { 606 SCSIZE nPos; 607 SCROW nStart=0; 608 if (!Search( nStartRow, nPos )) 609 { 610 DBG_ERROR("Search-Fehler"); 611 return; 612 } 613 614 do 615 { 616 const ScPatternAttr* pOldPattern = pData[nPos].pPattern; 617 const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); 618 const SfxPoolItem* pBoxItem = 0; 619 SfxItemState eState = rOldSet.GetItemState( ATTR_BORDER, sal_True, &pBoxItem ); 620 const SfxPoolItem* pTLBRItem = 0; 621 SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, sal_True, &pTLBRItem ); 622 const SfxPoolItem* pBLTRItem = 0; 623 SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, sal_True, &pBLTRItem ); 624 625 if ( (SFX_ITEM_SET == eState) || (SFX_ITEM_SET == eTLBRState) || (SFX_ITEM_SET == eBLTRState) ) 626 { 627 ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern); 628 SfxItemSet& rNewSet = pNewPattern->GetItemSet(); 629 SCROW nY1 = nStart; 630 SCROW nY2 = pData[nPos].nRow; 631 632 SvxBoxItem* pNewBoxItem = pBoxItem ? (SvxBoxItem*)pBoxItem->Clone() : 0; 633 SvxLineItem* pNewTLBRItem = pTLBRItem ? (SvxLineItem*)pTLBRItem->Clone() : 0; 634 SvxLineItem* pNewBLTRItem = pBLTRItem ? (SvxLineItem*)pBLTRItem->Clone() : 0; 635 636 // Linienattribute holen und mit Parametern aktualisieren 637 638 if ( !pLine ) 639 { 640 if( pNewBoxItem ) 641 { 642 if ( pNewBoxItem->GetTop() ) pNewBoxItem->SetLine( NULL, BOX_LINE_TOP ); 643 if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, BOX_LINE_BOTTOM ); 644 if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( NULL, BOX_LINE_LEFT ); 645 if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( NULL, BOX_LINE_RIGHT ); 646 } 647 if( pNewTLBRItem && pNewTLBRItem->GetLine() ) 648 pNewTLBRItem->SetLine( 0 ); 649 if( pNewBLTRItem && pNewBLTRItem->GetLine() ) 650 pNewBLTRItem->SetLine( 0 ); 651 } 652 else 653 { 654 if ( bColorOnly ) 655 { 656 Color aColor( pLine->GetColor() ); 657 if( pNewBoxItem ) 658 { 659 SET_LINECOLOR( pNewBoxItem->GetTop(), aColor ); 660 SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor ); 661 SET_LINECOLOR( pNewBoxItem->GetLeft(), aColor ); 662 SET_LINECOLOR( pNewBoxItem->GetRight(), aColor ); 663 } 664 if( pNewTLBRItem ) 665 SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor ); 666 if( pNewBLTRItem ) 667 SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor ); 668 } 669 else 670 { 671 if( pNewBoxItem ) 672 { 673 SET_LINE( pNewBoxItem->GetTop(), pLine ); 674 SET_LINE( pNewBoxItem->GetBottom(), pLine ); 675 SET_LINE( pNewBoxItem->GetLeft(), pLine ); 676 SET_LINE( pNewBoxItem->GetRight(), pLine ); 677 } 678 if( pNewTLBRItem ) 679 SET_LINE( pNewTLBRItem->GetLine(), pLine ); 680 if( pNewBLTRItem ) 681 SET_LINE( pNewBLTRItem->GetLine(), pLine ); 682 } 683 } 684 if( pNewBoxItem ) rNewSet.Put( *pNewBoxItem ); 685 if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem ); 686 if( pNewBLTRItem ) rNewSet.Put( *pNewBLTRItem ); 687 688 nStart = pData[nPos].nRow + 1; 689 690 if ( nY1 < nStartRow || nY2 > nEndRow ) 691 { 692 if (nY1 < nStartRow) nY1=nStartRow; 693 if (nY2 > nEndRow) nY2=nEndRow; 694 SetPatternArea( nY1, nY2, pNewPattern, sal_True ); 695 Search( nStart, nPos ); 696 } 697 else 698 { 699 //! aus Pool loeschen? 700 pDocument->GetPool()->Remove(*pData[nPos].pPattern); 701 pData[nPos].pPattern = (const ScPatternAttr*) 702 &pDocument->GetPool()->Put(*pNewPattern); 703 704 if (Concat(nPos)) 705 Search(nStart, nPos); 706 else 707 nPos++; 708 } 709 delete pNewBoxItem; 710 delete pNewTLBRItem; 711 delete pNewBLTRItem; 712 delete pNewPattern; 713 } 714 else 715 { 716 nStart = pData[nPos].nRow + 1; 717 nPos++; 718 } 719 } 720 while ((nStart <= nEndRow) && (nPos < nCount)); 721 } 722 } 723 724 #undef SET_LINECOLOR 725 #undef SET_LINE 726 727 728 void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache ) 729 { 730 #ifdef DBG_UTIL 731 TestData(); 732 #endif 733 734 if (ValidRow(nStartRow) && ValidRow(nEndRow)) 735 { 736 SCSIZE nPos; 737 SCROW nStart=0; 738 if (!Search( nStartRow, nPos )) 739 { 740 DBG_ERROR("Search-Fehler"); 741 return; 742 } 743 744 ScAddress aAdrStart( nCol, 0, nTab ); 745 ScAddress aAdrEnd ( nCol, 0, nTab ); 746 747 do 748 { 749 const ScPatternAttr* pOldPattern = pData[nPos].pPattern; 750 const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pCache->ApplyTo( *pOldPattern, sal_True ); 751 ScDocumentPool::CheckRef( *pOldPattern ); 752 ScDocumentPool::CheckRef( *pNewPattern ); 753 if (pNewPattern != pOldPattern) 754 { 755 SCROW nY1 = nStart; 756 SCROW nY2 = pData[nPos].nRow; 757 nStart = pData[nPos].nRow + 1; 758 759 if ( nY1 < nStartRow || nY2 > nEndRow ) 760 { 761 if (nY1 < nStartRow) nY1=nStartRow; 762 if (nY2 > nEndRow) nY2=nEndRow; 763 SetPatternArea( nY1, nY2, pNewPattern ); 764 Search( nStart, nPos ); 765 } 766 else 767 { 768 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert 769 770 const SfxItemSet& rNewSet = pNewPattern->GetItemSet(); 771 const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); 772 773 sal_Bool bNumFormatChanged; 774 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged, 775 rNewSet, rOldSet ) ) 776 { 777 aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 ); 778 aAdrEnd .SetRow( pData[nPos].nRow ); 779 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged ); 780 #ifdef DBG_INVALIDATE 781 DBGOUTPUT("ApplyCacheArea"); 782 #endif 783 } 784 785 // bedingte Formate neu gesetzt oder geloescht ? 786 787 if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) ) 788 { 789 pDocument->ConditionalChanged( ((const SfxUInt32Item&) 790 rOldSet.Get(ATTR_CONDITIONAL)).GetValue() ); 791 pDocument->ConditionalChanged( ((const SfxUInt32Item&) 792 rNewSet.Get(ATTR_CONDITIONAL)).GetValue() ); 793 } 794 795 pDocument->GetPool()->Remove(*pData[nPos].pPattern); 796 pData[nPos].pPattern = pNewPattern; 797 if (Concat(nPos)) 798 Search(nStart, nPos); 799 else 800 ++nPos; 801 } 802 } 803 else 804 { 805 //!!!!!!!!!!!!!!!!!! mit diesem Remove gibt es Abstuerze (Calc1 Import) 806 //! pDocument->GetPool()->Remove(*pNewPattern); 807 nStart = pData[nPos].nRow + 1; 808 ++nPos; 809 } 810 } 811 while (nStart <= nEndRow); 812 813 if (pDocument->IsStreamValid(nTab)) 814 pDocument->SetStreamValid(nTab, sal_False); 815 } 816 817 #ifdef DBG_UTIL 818 TestData(); 819 #endif 820 } 821 822 823 void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource ) 824 { 825 const SfxPoolItem* pNewItem; 826 const SfxPoolItem* pOldItem; 827 for (sal_uInt16 nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++) 828 { 829 // pMergeSet hat keinen Parent 830 SfxItemState eOldState = rMergeSet.GetItemState( nId, sal_False, &pOldItem ); 831 832 if ( eOldState == SFX_ITEM_DEFAULT ) // Default 833 { 834 SfxItemState eNewState = rSource.GetItemState( nId, sal_True, &pNewItem ); 835 if ( eNewState == SFX_ITEM_SET ) 836 { 837 if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) ) 838 rMergeSet.InvalidateItem( nId ); 839 } 840 } 841 else if ( eOldState == SFX_ITEM_SET ) // Item gesetzt 842 { 843 SfxItemState eNewState = rSource.GetItemState( nId, sal_True, &pNewItem ); 844 if ( eNewState == SFX_ITEM_SET ) 845 { 846 if ( pNewItem != pOldItem ) // beide gepuhlt 847 rMergeSet.InvalidateItem( nId ); 848 } 849 else // Default 850 { 851 if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) ) 852 rMergeSet.InvalidateItem( nId ); 853 } 854 } 855 // Dontcare bleibt Dontcare 856 } 857 } 858 859 860 void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow, 861 ScMergePatternState& rState, sal_Bool bDeep ) const 862 { 863 if (ValidRow(nStartRow) && ValidRow(nEndRow)) 864 { 865 SCSIZE nPos; 866 SCROW nStart=0; 867 if (!Search( nStartRow, nPos )) 868 { 869 DBG_ERROR("Search-Fehler"); 870 return; 871 } 872 873 do 874 { 875 // gleiche Patterns muessen nicht mehrfach angesehen werden 876 877 const ScPatternAttr* pPattern = pData[nPos].pPattern; 878 if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 ) 879 { 880 const SfxItemSet& rThisSet = pPattern->GetItemSet(); 881 if (rState.pItemSet) 882 { 883 // (*ppSet)->MergeValues( rThisSet, sal_False ); 884 // geht nicht, weil die Vorlagen nicht beruecksichtigt werden 885 886 if (bDeep) 887 lcl_MergeDeep( *rState.pItemSet, rThisSet ); 888 else 889 rState.pItemSet->MergeValues( rThisSet, sal_False ); 890 } 891 else 892 { 893 // erstes Pattern - in Set ohne Parent kopieren 894 rState.pItemSet = new SfxItemSet( *rThisSet.GetPool(), rThisSet.GetRanges() ); 895 rState.pItemSet->Set( rThisSet, bDeep ); 896 } 897 898 rState.pOld2 = rState.pOld1; 899 rState.pOld1 = pPattern; 900 } 901 902 nStart = pData[nPos].nRow + 1; 903 ++nPos; 904 } 905 while (nStart <= nEndRow); 906 } 907 } 908 909 910 911 // Umrandung zusammenbauen 912 913 sal_Bool lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine, 914 sal_uInt8& rModified, const SvxBorderLine*& rpNew ) 915 { 916 if (rModified == SC_LINE_DONTCARE) 917 return sal_False; // weiter geht's nicht 918 919 if (rModified == SC_LINE_EMPTY) 920 { 921 rModified = SC_LINE_SET; 922 rpNew = pNewLine; 923 return sal_True; // zum ersten mal gesetzt 924 } 925 926 if (pOldLine == pNewLine) 927 { 928 rpNew = pOldLine; 929 return sal_False; 930 } 931 932 if (pOldLine && pNewLine) 933 if (*pOldLine == *pNewLine) 934 { 935 rpNew = pOldLine; 936 return sal_False; 937 } 938 939 rModified = SC_LINE_DONTCARE; 940 rpNew = NULL; 941 return sal_True; // andere Linie -> dontcare 942 } 943 944 945 void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, 946 ScLineFlags& rFlags, const ScPatternAttr* pPattern, 947 sal_Bool bLeft, SCCOL nDistRight, sal_Bool bTop, SCROW nDistBottom ) 948 { 949 // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst: 950 const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE); 951 if ( rMerge.GetColMerge() == nDistRight + 1 ) 952 nDistRight = 0; 953 if ( rMerge.GetRowMerge() == nDistBottom + 1 ) 954 nDistBottom = 0; 955 956 const SvxBoxItem* pCellFrame = (SvxBoxItem*) &pPattern->GetItemSet().Get( ATTR_BORDER ); 957 const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft(); 958 const SvxBorderLine* pRightAttr = pCellFrame->GetRight(); 959 const SvxBorderLine* pTopAttr = pCellFrame->GetTop(); 960 const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom(); 961 const SvxBorderLine* pNew; 962 963 if (bTop) 964 { 965 if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew )) 966 pLineOuter->SetLine( pNew, BOX_LINE_TOP ); 967 } 968 else 969 { 970 if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew )) 971 pLineInner->SetLine( pNew, BOXINFO_LINE_HORI ); 972 } 973 974 if (nDistBottom == 0) 975 { 976 if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew )) 977 pLineOuter->SetLine( pNew, BOX_LINE_BOTTOM ); 978 } 979 else 980 { 981 if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew )) 982 pLineInner->SetLine( pNew, BOXINFO_LINE_HORI ); 983 } 984 985 if (bLeft) 986 { 987 if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew )) 988 pLineOuter->SetLine( pNew, BOX_LINE_LEFT ); 989 } 990 else 991 { 992 if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew )) 993 pLineInner->SetLine( pNew, BOXINFO_LINE_VERT ); 994 } 995 996 if (nDistRight == 0) 997 { 998 if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew )) 999 pLineOuter->SetLine( pNew, BOX_LINE_RIGHT ); 1000 } 1001 else 1002 { 1003 if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew )) 1004 pLineInner->SetLine( pNew, BOXINFO_LINE_VERT ); 1005 } 1006 } 1007 1008 1009 void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, 1010 ScLineFlags& rFlags, 1011 SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) const 1012 { 1013 const ScPatternAttr* pPattern; 1014 1015 if (nStartRow == nEndRow) 1016 { 1017 pPattern = GetPattern( nStartRow ); 1018 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_True, 0 ); 1019 } 1020 else 1021 { 1022 pPattern = GetPattern( nStartRow ); 1023 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_True, 1024 nEndRow-nStartRow ); 1025 1026 SCSIZE nStartIndex; 1027 SCSIZE nEndIndex; 1028 Search( nStartRow+1, nStartIndex ); 1029 Search( nEndRow-1, nEndIndex ); 1030 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++) 1031 { 1032 pPattern = (ScPatternAttr*) pData[i].pPattern; 1033 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_False, 1034 nEndRow - Min( pData[i].nRow, (SCROW)(nEndRow-1) ) ); 1035 // nDistBottom hier immer > 0 1036 } 1037 1038 pPattern = GetPattern( nEndRow ); 1039 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, sal_False, 0 ); 1040 } 1041 } 1042 1043 // 1044 // Rahmen anwenden 1045 // 1046 1047 // ApplyFrame - auf einen Eintrag im Array 1048 1049 1050 sal_Bool ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem, 1051 const SvxBoxInfoItem* pBoxInfoItem, 1052 SCROW nStartRow, SCROW nEndRow, 1053 sal_Bool bLeft, SCCOL nDistRight, sal_Bool bTop, SCROW nDistBottom ) 1054 { 1055 DBG_ASSERT( pBoxItem && pBoxInfoItem, "Linienattribute fehlen!" ); 1056 1057 const ScPatternAttr* pPattern = GetPattern( nStartRow ); 1058 const SvxBoxItem* pOldFrame = (const SvxBoxItem*) 1059 &pPattern->GetItemSet().Get( ATTR_BORDER ); 1060 1061 // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst: 1062 const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE); 1063 if ( rMerge.GetColMerge() == nDistRight + 1 ) 1064 nDistRight = 0; 1065 if ( rMerge.GetRowMerge() == nDistBottom + 1 ) 1066 nDistBottom = 0; 1067 1068 SvxBoxItem aNewFrame( *pOldFrame ); 1069 1070 if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) ) 1071 aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(), 1072 BOX_LINE_LEFT ); 1073 if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) ) 1074 aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(), 1075 BOX_LINE_RIGHT ); 1076 if ( bTop ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) ) 1077 aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(), 1078 BOX_LINE_TOP ); 1079 if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) ) 1080 aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(), 1081 BOX_LINE_BOTTOM ); 1082 1083 if (aNewFrame == *pOldFrame) 1084 { 1085 // nothing to do 1086 return sal_False; 1087 } 1088 else 1089 { 1090 SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame ); 1091 ApplyCacheArea( nStartRow, nEndRow, &aCache ); 1092 1093 /* ScPatternAttr* pNewPattern = (ScPatternAttr*) pPattern->Clone(); 1094 pNewPattern->GetItemSet().Put( aNewFrame ); 1095 SetPatternArea( nStartRow, nEndRow, pNewPattern, sal_True ); 1096 */ 1097 return sal_True; 1098 } 1099 } 1100 1101 1102 void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner, 1103 SCROW nStartRow, SCROW nEndRow, sal_Bool bLeft, SCCOL nDistRight ) 1104 { 1105 if (nStartRow == nEndRow) 1106 ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, sal_True, 0 ); 1107 else 1108 { 1109 ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight, 1110 sal_True, nEndRow-nStartRow ); 1111 1112 if ( nEndRow > nStartRow+1 ) // innerer Teil vorhanden? 1113 { 1114 SCSIZE nStartIndex; 1115 SCSIZE nEndIndex; 1116 Search( nStartRow+1, nStartIndex ); 1117 Search( nEndRow-1, nEndIndex ); 1118 SCROW nTmpStart = nStartRow+1; 1119 SCROW nTmpEnd; 1120 for (SCSIZE i=nStartIndex; i<=nEndIndex;) 1121 { 1122 nTmpEnd = Min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) ); 1123 sal_Bool bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd, 1124 bLeft, nDistRight, sal_False, nEndRow-nTmpEnd ); 1125 nTmpStart = nTmpEnd+1; 1126 if (bChanged) 1127 { 1128 Search(nTmpStart, i); 1129 Search(nEndRow-1, nEndIndex); 1130 } 1131 else 1132 i++; 1133 } 1134 } 1135 1136 ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, sal_False, 0 ); 1137 } 1138 } 1139 1140 1141 long lcl_LineSize( const SvxBorderLine& rLine ) 1142 { 1143 // nur eine Linie -> halbe Breite, min. 20 1144 // doppelte Linie -> halber Abstand + eine Linie (je min. 20) 1145 1146 long nTotal = 0; 1147 sal_uInt16 nWidth = Max( rLine.GetOutWidth(), rLine.GetInWidth() ); 1148 sal_uInt16 nDist = rLine.GetDistance(); 1149 if (nDist) 1150 { 1151 DBG_ASSERT( rLine.GetOutWidth() && rLine.GetInWidth(), 1152 "Linie hat Abstand, aber nur eine Breite ???" ); 1153 1154 // nTotal += ( nDist > 40 ) ? ( nDist / 2 ) : 20; 1155 nTotal += ( nDist > 20 ) ? nDist : 20; 1156 nTotal += ( nWidth > 20 ) ? nWidth : 20; 1157 } 1158 else if (nWidth) 1159 // nTotal += ( nWidth > 40 ) ? ( nWidth / 2 ) : 20; 1160 nTotal += ( nWidth > 20 ) ? nWidth : 20; 1161 1162 //! auch halbieren ??? 1163 1164 return nTotal; 1165 } 1166 1167 1168 sal_Bool ScAttrArray::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes, 1169 sal_Bool bLeft, sal_Bool bRight ) const 1170 { 1171 SCSIZE nStartIndex; 1172 SCSIZE nEndIndex; 1173 Search( nRow1, nStartIndex ); 1174 Search( nRow2, nEndIndex ); 1175 sal_Bool bFound = sal_False; 1176 1177 const SvxBoxItem* pItem = 0; 1178 const SvxBorderLine* pLine = 0; 1179 long nCmp; 1180 1181 // oben 1182 1183 pItem = (const SvxBoxItem*) &pData[nStartIndex].pPattern->GetItem(ATTR_BORDER); 1184 pLine = pItem->GetTop(); 1185 if (pLine) 1186 { 1187 nCmp = lcl_LineSize(*pLine); 1188 if ( nCmp > rSizes.Top() ) 1189 rSizes.Top() = nCmp; 1190 bFound = sal_True; 1191 } 1192 1193 // unten 1194 1195 if ( nEndIndex != nStartIndex ) 1196 pItem = (const SvxBoxItem*) &pData[nEndIndex].pPattern->GetItem(ATTR_BORDER); 1197 pLine = pItem->GetBottom(); 1198 if (pLine) 1199 { 1200 nCmp = lcl_LineSize(*pLine); 1201 if ( nCmp > rSizes.Bottom() ) 1202 rSizes.Bottom() = nCmp; 1203 bFound = sal_True; 1204 } 1205 1206 if ( bLeft || bRight ) 1207 for ( SCSIZE i=nStartIndex; i<=nEndIndex; i++) 1208 { 1209 pItem = (const SvxBoxItem*) &pData[i].pPattern->GetItem(ATTR_BORDER); 1210 1211 // links 1212 1213 if (bLeft) 1214 { 1215 pLine = pItem->GetLeft(); 1216 if (pLine) 1217 { 1218 nCmp = lcl_LineSize(*pLine); 1219 if ( nCmp > rSizes.Left() ) 1220 rSizes.Left() = nCmp; 1221 bFound = sal_True; 1222 } 1223 } 1224 1225 // rechts 1226 1227 if (bRight) 1228 { 1229 pLine = pItem->GetRight(); 1230 if (pLine) 1231 { 1232 nCmp = lcl_LineSize(*pLine); 1233 if ( nCmp > rSizes.Right() ) 1234 rSizes.Right() = nCmp; 1235 bFound = sal_True; 1236 } 1237 } 1238 } 1239 1240 return bFound; 1241 } 1242 1243 // Testen, ob Bereich bestimmtes Attribut enthaelt 1244 1245 bool ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, sal_uInt16 nMask ) const 1246 { 1247 SCSIZE nStartIndex; 1248 SCSIZE nEndIndex; 1249 Search( nRow1, nStartIndex ); 1250 Search( nRow2, nEndIndex ); 1251 bool bFound = false; 1252 1253 for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++) 1254 { 1255 const ScPatternAttr* pPattern = pData[i].pPattern; 1256 if ( nMask & HASATTR_MERGED ) 1257 { 1258 const ScMergeAttr* pMerge = 1259 (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE ); 1260 if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 ) 1261 bFound = true; 1262 } 1263 if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) ) 1264 { 1265 const ScMergeFlagAttr* pMergeFlag = 1266 (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG ); 1267 if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() ) 1268 bFound = true; 1269 if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() ) 1270 bFound = true; 1271 if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() ) 1272 bFound = true; 1273 } 1274 if ( nMask & HASATTR_LINES ) 1275 { 1276 const SvxBoxItem* pBox = 1277 (const SvxBoxItem*) &pPattern->GetItem( ATTR_BORDER ); 1278 if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() ) 1279 bFound = true; 1280 } 1281 if ( nMask & HASATTR_SHADOW ) 1282 { 1283 const SvxShadowItem* pShadow = 1284 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW ); 1285 if ( pShadow->GetLocation() != SVX_SHADOW_NONE ) 1286 bFound = true; 1287 } 1288 if ( nMask & HASATTR_CONDITIONAL ) 1289 { 1290 const SfxUInt32Item* pConditional = 1291 (const SfxUInt32Item*) &pPattern->GetItem( ATTR_CONDITIONAL ); 1292 if ( pConditional->GetValue() != 0 ) 1293 bFound = true; 1294 } 1295 if ( nMask & HASATTR_PROTECTED ) 1296 { 1297 const ScProtectionAttr* pProtect = 1298 (const ScProtectionAttr*) &pPattern->GetItem( ATTR_PROTECTION ); 1299 if ( pProtect->GetProtection() || pProtect->GetHideCell() ) 1300 bFound = true; 1301 } 1302 if ( nMask & HASATTR_ROTATE ) 1303 { 1304 const SfxInt32Item* pRotate = 1305 (const SfxInt32Item*) &pPattern->GetItem( ATTR_ROTATE_VALUE ); 1306 // 90 or 270 degrees is former SvxOrientationItem - only look for other values 1307 // (see ScPatternAttr::GetCellOrientation) 1308 sal_Int32 nAngle = pRotate->GetValue(); 1309 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 ) 1310 bFound = true; 1311 } 1312 if ( nMask & HASATTR_NEEDHEIGHT ) 1313 { 1314 if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD) 1315 bFound = true; 1316 else if (((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue()) 1317 bFound = true; 1318 else if ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern-> 1319 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK) 1320 bFound = true; 1321 else if (((const SfxUInt32Item&)pPattern->GetItem( ATTR_CONDITIONAL )).GetValue()) 1322 bFound = true; 1323 else if (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue()) 1324 bFound = true; 1325 } 1326 if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) ) 1327 { 1328 const SvxShadowItem* pShadow = 1329 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW ); 1330 SvxShadowLocation eLoc = pShadow->GetLocation(); 1331 if ( nMask & HASATTR_SHADOW_RIGHT ) 1332 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT ) 1333 bFound = true; 1334 if ( nMask & HASATTR_SHADOW_DOWN ) 1335 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT ) 1336 bFound = true; 1337 } 1338 if ( nMask & HASATTR_RTL ) 1339 { 1340 const SvxFrameDirectionItem& rDirection = 1341 (const SvxFrameDirectionItem&) pPattern->GetItem( ATTR_WRITINGDIR ); 1342 if ( rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP ) 1343 bFound = true; 1344 } 1345 if ( nMask & HASATTR_RIGHTORCENTER ) 1346 { 1347 // called only if the sheet is LTR, so physical=logical alignment can be assumed 1348 SvxCellHorJustify eHorJust = (SvxCellHorJustify) 1349 ((const SvxHorJustifyItem&) pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue(); 1350 if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER ) 1351 bFound = true; 1352 } 1353 } 1354 1355 return bFound; 1356 } 1357 1358 // Bereich um evtl. enthaltene Zusammenfassungen erweitern 1359 // und evtl. MergeFlag anpassen (bRefresh) 1360 1361 sal_Bool ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow, 1362 SCCOL& rPaintCol, SCROW& rPaintRow, 1363 sal_Bool bRefresh, sal_Bool bAttrs ) 1364 { 1365 const ScPatternAttr* pPattern; 1366 const ScMergeAttr* pItem; 1367 SCSIZE nStartIndex; 1368 SCSIZE nEndIndex; 1369 Search( nStartRow, nStartIndex ); 1370 Search( nEndRow, nEndIndex ); 1371 sal_Bool bFound = sal_False; 1372 1373 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++) 1374 { 1375 pPattern = pData[i].pPattern; 1376 pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE ); 1377 SCsCOL nCountX = pItem->GetColMerge(); 1378 SCsROW nCountY = pItem->GetRowMerge(); 1379 if (nCountX>1 || nCountY>1) 1380 { 1381 SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0; 1382 SCCOL nMergeEndCol = nThisCol + nCountX - 1; 1383 SCROW nMergeEndRow = nThisRow + nCountY - 1; 1384 if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL) 1385 rPaintCol = nMergeEndCol; 1386 if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW) 1387 rPaintRow = nMergeEndRow; 1388 bFound = sal_True; 1389 1390 if (bAttrs) 1391 { 1392 const SvxShadowItem* pShadow = 1393 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW ); 1394 SvxShadowLocation eLoc = pShadow->GetLocation(); 1395 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT ) 1396 if ( nMergeEndCol+1 > rPaintCol && nMergeEndCol < MAXCOL ) 1397 rPaintCol = nMergeEndCol+1; 1398 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT ) 1399 if ( nMergeEndRow+1 > rPaintRow && nMergeEndRow < MAXROW ) 1400 rPaintRow = nMergeEndRow+1; 1401 } 1402 1403 if (bRefresh) 1404 { 1405 if ( nMergeEndCol > nThisCol ) 1406 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow, 1407 nTab, SC_MF_HOR ); 1408 if ( nMergeEndRow > nThisRow ) 1409 pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow, 1410 nTab, SC_MF_VER ); 1411 if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow ) 1412 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow, 1413 nTab, SC_MF_HOR | SC_MF_VER ); 1414 1415 Search( nThisRow, i ); // Daten wurden veraendert 1416 Search( nStartRow, nStartIndex ); 1417 Search( nEndRow, nEndIndex ); 1418 } 1419 } 1420 } 1421 1422 return bFound; 1423 } 1424 1425 1426 sal_Bool ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow) 1427 { 1428 sal_Bool bFound = sal_False; 1429 const ScPatternAttr* pPattern; 1430 const ScMergeAttr* pItem; 1431 SCSIZE nIndex; 1432 1433 Search( nStartRow, nIndex ); 1434 SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; 1435 if (nThisStart < nStartRow) 1436 nThisStart = nStartRow; 1437 1438 while ( nThisStart <= nEndRow ) 1439 { 1440 SCROW nThisEnd = pData[nIndex].nRow; 1441 if (nThisEnd > nEndRow) 1442 nThisEnd = nEndRow; 1443 1444 pPattern = pData[nIndex].pPattern; 1445 pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE ); 1446 SCsCOL nCountX = pItem->GetColMerge(); 1447 SCsROW nCountY = pItem->GetRowMerge(); 1448 if (nCountX>1 || nCountY>1) 1449 { 1450 const ScMergeAttr* pAttr = (const ScMergeAttr*) 1451 &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE ); 1452 const ScMergeFlagAttr* pFlagAttr = (const ScMergeFlagAttr*) 1453 &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG ); 1454 1455 DBG_ASSERT( nCountY==1 || nThisStart==nThisEnd, "was'n hier los?" ); 1456 1457 SCCOL nThisCol = nCol; 1458 SCCOL nMergeEndCol = nThisCol + nCountX - 1; 1459 SCROW nMergeEndRow = nThisEnd + nCountY - 1; 1460 1461 //! ApplyAttr fuer Bereiche !!! 1462 1463 for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++) 1464 pDocument->ApplyAttr( nThisCol, nThisRow, nTab, *pAttr ); 1465 1466 ScPatternAttr* pNewPattern = new ScPatternAttr( pDocument->GetPool() ); 1467 SfxItemSet* pSet = &pNewPattern->GetItemSet(); 1468 pSet->Put( *pFlagAttr ); 1469 pDocument->ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow, 1470 nTab, *pNewPattern ); 1471 delete pNewPattern; 1472 1473 Search( nThisEnd, nIndex ); // Daten wurden veraendert !!! 1474 } 1475 1476 ++nIndex; 1477 if ( nIndex < nCount ) 1478 nThisStart = pData[nIndex-1].nRow+1; 1479 else 1480 nThisStart = MAXROW+1; // Ende 1481 } 1482 1483 return bFound; 1484 } 1485 1486 // Bereich loeschen, aber Merge-Flags stehenlassen 1487 1488 void ScAttrArray::DeleteAreaSafe(SCROW nStartRow, SCROW nEndRow) 1489 { 1490 SetPatternAreaSafe( nStartRow, nEndRow, pDocument->GetDefPattern(), sal_True ); 1491 } 1492 1493 1494 void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow, 1495 const ScPatternAttr* pWantedPattern, sal_Bool bDefault ) 1496 { 1497 const ScPatternAttr* pOldPattern; 1498 const ScMergeFlagAttr* pItem; 1499 1500 SCSIZE nIndex; 1501 SCROW nRow; 1502 SCROW nThisRow; 1503 sal_Bool bFirstUse = sal_True; 1504 1505 Search( nStartRow, nIndex ); 1506 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; 1507 while ( nThisRow <= nEndRow ) 1508 { 1509 pOldPattern = pData[nIndex].pPattern; 1510 if (pOldPattern != pWantedPattern) //! else-Zweig ? 1511 { 1512 if (nThisRow < nStartRow) nThisRow = nStartRow; 1513 nRow = pData[nIndex].nRow; 1514 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow ); 1515 pItem = (const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ); 1516 1517 if (pItem->IsOverlapped() || pItem->HasAutoFilter()) 1518 { 1519 // #108045# default-constructing a ScPatternAttr for DeleteArea doesn't work 1520 // because it would have no cell style information. 1521 // Instead, the document's GetDefPattern is copied. Since it is passed as 1522 // pWantedPattern, no special treatment of default is needed here anymore. 1523 ScPatternAttr* pNewPattern = new ScPatternAttr( *pWantedPattern ); 1524 SfxItemSet* pSet = &pNewPattern->GetItemSet(); 1525 pSet->Put( *pItem ); 1526 SetPatternArea( nThisRow, nAttrRow, pNewPattern, sal_True ); 1527 delete pNewPattern; 1528 } 1529 else 1530 { 1531 if ( !bDefault ) 1532 { 1533 if (bFirstUse) 1534 bFirstUse = sal_False; 1535 else 1536 pDocument->GetPool()->Put( *pWantedPattern ); // im Pool ist es schon! 1537 } 1538 SetPatternArea( nThisRow, nAttrRow, pWantedPattern ); 1539 } 1540 1541 Search( nThisRow, nIndex ); // Daten wurden veraendert !!! 1542 } 1543 1544 ++nIndex; 1545 nThisRow = pData[nIndex-1].nRow+1; 1546 } 1547 } 1548 1549 1550 sal_Bool ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags ) 1551 { 1552 const ScPatternAttr* pOldPattern; 1553 1554 sal_Int16 nOldValue; 1555 SCSIZE nIndex; 1556 SCROW nRow; 1557 SCROW nThisRow; 1558 sal_Bool bChanged = sal_False; 1559 1560 Search( nStartRow, nIndex ); 1561 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; 1562 if (nThisRow < nStartRow) nThisRow = nStartRow; 1563 1564 while ( nThisRow <= nEndRow ) 1565 { 1566 pOldPattern = pData[nIndex].pPattern; 1567 nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue(); 1568 if ( (nOldValue | nFlags) != nOldValue ) 1569 { 1570 nRow = pData[nIndex].nRow; 1571 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow ); 1572 ScPatternAttr aNewPattern(*pOldPattern); 1573 aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) ); 1574 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True ); 1575 Search( nThisRow, nIndex ); // Daten wurden veraendert !!! 1576 bChanged = sal_True; 1577 } 1578 1579 ++nIndex; 1580 nThisRow = pData[nIndex-1].nRow+1; 1581 } 1582 1583 return bChanged; 1584 } 1585 1586 1587 sal_Bool ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, sal_Int16 nFlags ) 1588 { 1589 const ScPatternAttr* pOldPattern; 1590 1591 sal_Int16 nOldValue; 1592 SCSIZE nIndex; 1593 SCROW nRow; 1594 SCROW nThisRow; 1595 sal_Bool bChanged = sal_False; 1596 1597 Search( nStartRow, nIndex ); 1598 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; 1599 if (nThisRow < nStartRow) nThisRow = nStartRow; 1600 1601 while ( nThisRow <= nEndRow ) 1602 { 1603 pOldPattern = pData[nIndex].pPattern; 1604 nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue(); 1605 if ( (nOldValue & ~nFlags) != nOldValue ) 1606 { 1607 nRow = pData[nIndex].nRow; 1608 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow ); 1609 ScPatternAttr aNewPattern(*pOldPattern); 1610 aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) ); 1611 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True ); 1612 Search( nThisRow, nIndex ); // Daten wurden veraendert !!! 1613 bChanged = sal_True; 1614 } 1615 1616 ++nIndex; 1617 nThisRow = pData[nIndex-1].nRow+1; 1618 } 1619 1620 return bChanged; 1621 } 1622 1623 1624 void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const sal_uInt16* pWhich ) 1625 { 1626 const ScPatternAttr* pOldPattern; 1627 1628 SCSIZE nIndex; 1629 SCROW nRow; 1630 SCROW nThisRow; 1631 1632 Search( nStartRow, nIndex ); 1633 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; 1634 if (nThisRow < nStartRow) nThisRow = nStartRow; 1635 1636 while ( nThisRow <= nEndRow ) 1637 { 1638 pOldPattern = pData[nIndex].pPattern; 1639 if ( pOldPattern->HasItemsSet( pWhich ) ) 1640 { 1641 ScPatternAttr aNewPattern(*pOldPattern); 1642 aNewPattern.ClearItems( pWhich ); 1643 1644 nRow = pData[nIndex].nRow; 1645 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow ); 1646 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True ); 1647 Search( nThisRow, nIndex ); // Daten wurden veraendert !!! 1648 } 1649 1650 ++nIndex; 1651 nThisRow = pData[nIndex-1].nRow+1; 1652 } 1653 } 1654 1655 1656 void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, sal_Bool bIncrement ) 1657 { 1658 SCSIZE nIndex; 1659 Search( nStartRow, nIndex ); 1660 SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; 1661 if (nThisStart < nStartRow) nThisStart = nStartRow; 1662 1663 while ( nThisStart <= nEndRow ) 1664 { 1665 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern; 1666 const SfxItemSet& rOldSet = pOldPattern->GetItemSet(); 1667 const SfxPoolItem* pItem; 1668 1669 sal_Bool bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, sal_False, &pItem ) != SFX_ITEM_SET 1670 || ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT ); 1671 sal_uInt16 nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue(); 1672 sal_uInt16 nNewValue = nOldValue; 1673 if ( bIncrement ) 1674 { 1675 if ( nNewValue < SC_MAX_INDENT ) 1676 { 1677 nNewValue += SC_INDENT_STEP; 1678 if ( nNewValue > SC_MAX_INDENT ) nNewValue = SC_MAX_INDENT; 1679 } 1680 } 1681 else 1682 { 1683 if ( nNewValue > 0 ) 1684 { 1685 if ( nNewValue > SC_INDENT_STEP ) 1686 nNewValue -= SC_INDENT_STEP; 1687 else 1688 nNewValue = 0; 1689 } 1690 } 1691 1692 if ( bNeedJust || nNewValue != nOldValue ) 1693 { 1694 SCROW nThisEnd = pData[nIndex].nRow; 1695 SCROW nAttrRow = Min( nThisEnd, nEndRow ); 1696 ScPatternAttr aNewPattern(*pOldPattern); 1697 aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) ); 1698 if ( bNeedJust ) 1699 aNewPattern.GetItemSet().Put( 1700 SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) ); 1701 SetPatternArea( nThisStart, nAttrRow, &aNewPattern, sal_True ); 1702 1703 nThisStart = nThisEnd + 1; 1704 Search( nThisStart, nIndex ); // Daten wurden veraendert !!! 1705 } 1706 else 1707 { 1708 nThisStart = pData[nIndex].nRow + 1; // weiterzaehlen... 1709 ++nIndex; 1710 } 1711 } 1712 } 1713 1714 1715 SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, sal_Bool bUp ) const 1716 { 1717 long nRet = nRow; 1718 if (VALIDROW(nRow)) 1719 { 1720 SCSIZE nIndex; 1721 Search(nRow, nIndex); 1722 while (((const ScProtectionAttr&)pData[nIndex].pPattern-> 1723 GetItem(ATTR_PROTECTION)).GetProtection()) 1724 { 1725 if (bUp) 1726 { 1727 if (nIndex==0) 1728 return -1; // nichts gefunden 1729 --nIndex; 1730 nRet = pData[nIndex].nRow; 1731 } 1732 else 1733 { 1734 nRet = pData[nIndex].nRow+1; 1735 ++nIndex; 1736 if (nIndex>=nCount) 1737 return MAXROW+1; // nichts gefunden 1738 } 1739 } 1740 } 1741 return nRet; 1742 } 1743 1744 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset ) 1745 { 1746 SCROW nStart = 0; 1747 SCSIZE nPos = 0; 1748 while (nPos < nCount) 1749 { 1750 SCROW nEnd = pData[nPos].nRow; 1751 if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet) 1752 { 1753 // for (SCROW nRow = nStart; nRow <= nEnd; nRow++) 1754 // pUsed[nRow] = sal_True; 1755 1756 rUsedRows.setTrue(nStart, nEnd); 1757 1758 if (bReset) 1759 { 1760 ScPatternAttr* pNewPattern = new ScPatternAttr(*pData[nPos].pPattern); 1761 pDocument->GetPool()->Remove(*pData[nPos].pPattern); 1762 pNewPattern->SetStyleSheet( (ScStyleSheet*) 1763 pDocument->GetStyleSheetPool()-> 1764 Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD), 1765 SFX_STYLE_FAMILY_PARA, 1766 SFXSTYLEBIT_AUTO | SCSTYLEBIT_STANDARD ) ); 1767 pData[nPos].pPattern = (const ScPatternAttr*) 1768 &pDocument->GetPool()->Put(*pNewPattern); 1769 delete pNewPattern; 1770 1771 if (Concat(nPos)) 1772 { 1773 Search(nStart, nPos); 1774 --nPos; // wegen ++ am Ende 1775 } 1776 } 1777 } 1778 nStart = nEnd + 1; 1779 ++nPos; 1780 } 1781 } 1782 1783 1784 sal_Bool ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle, 1785 sal_Bool bGatherAllStyles ) const 1786 { 1787 sal_Bool bIsUsed = sal_False; 1788 SCSIZE nPos = 0; 1789 1790 while ( nPos < nCount ) 1791 { 1792 const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet(); 1793 if ( pStyle ) 1794 { 1795 pStyle->SetUsage( ScStyleSheet::USED ); 1796 if ( pStyle == &rStyle ) 1797 { 1798 if ( !bGatherAllStyles ) 1799 return sal_True; 1800 bIsUsed = sal_True; 1801 } 1802 } 1803 nPos++; 1804 } 1805 1806 return bIsUsed; 1807 } 1808 1809 1810 sal_Bool ScAttrArray::IsEmpty() const 1811 { 1812 if (nCount == 1) 1813 { 1814 if ( pData[0].pPattern != pDocument->GetDefPattern() ) 1815 return sal_False; 1816 else 1817 return sal_True; 1818 } 1819 else 1820 return sal_False; 1821 } 1822 1823 1824 //UNUSED2008-05 SCROW ScAttrArray::GetFirstEntryPos() const 1825 //UNUSED2008-05 { 1826 //UNUSED2008-05 DBG_ASSERT( nCount, "nCount = 0" ); 1827 //UNUSED2008-05 1828 //UNUSED2008-05 if ( pData[0].pPattern != pDocument->GetDefPattern() ) 1829 //UNUSED2008-05 return 0; 1830 //UNUSED2008-05 else 1831 //UNUSED2008-05 { 1832 //UNUSED2008-05 if (nCount==1) 1833 //UNUSED2008-05 return 0; // leer 1834 //UNUSED2008-05 else 1835 //UNUSED2008-05 return pData[0].nRow + 1; 1836 //UNUSED2008-05 } 1837 //UNUSED2008-05 } 1838 //UNUSED2008-05 1839 //UNUSED2008-05 1840 //UNUSED2008-05 SCROW ScAttrArray::GetLastEntryPos( sal_Bool bIncludeBottom ) const 1841 //UNUSED2008-05 { 1842 //UNUSED2008-05 DBG_ASSERT( nCount, "nCount == 0" ); 1843 //UNUSED2008-05 1844 //UNUSED2008-05 if (bIncludeBottom) 1845 //UNUSED2008-05 bIncludeBottom = ( pData[nCount-1].pPattern != pDocument->GetDefPattern() ); 1846 //UNUSED2008-05 1847 //UNUSED2008-05 if (bIncludeBottom) 1848 //UNUSED2008-05 return MAXROW; 1849 //UNUSED2008-05 else 1850 //UNUSED2008-05 { 1851 //UNUSED2008-05 if (nCount<=1) 1852 //UNUSED2008-05 return 0; // leer 1853 //UNUSED2008-05 else 1854 //UNUSED2008-05 return pData[nCount-2].nRow; 1855 //UNUSED2008-05 } 1856 //UNUSED2008-05 } 1857 1858 1859 sal_Bool ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const 1860 { 1861 DBG_ASSERT( nCount, "nCount == 0" ); 1862 1863 sal_Bool bFound = sal_False; 1864 SCSIZE nStart = 0; 1865 1866 // Skip first entry if more than 1 row. 1867 // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr. 1868 1869 SCSIZE nVisStart = 1; 1870 while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) ) 1871 ++nVisStart; 1872 if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 ) // more than 1 row? 1873 nStart = nVisStart; 1874 1875 while ( nStart < nCount && !bFound ) 1876 { 1877 if ( pData[nStart].pPattern->IsVisible() ) 1878 { 1879 rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0; 1880 bFound = sal_True; 1881 } 1882 else 1883 ++nStart; 1884 } 1885 1886 return bFound; 1887 } 1888 1889 // size (rows) of a range of attributes after cell content where the search is stopped 1890 // (more than a default page size, 2*42 because it's as good as any number) 1891 1892 const SCROW SC_VISATTR_STOP = 84; 1893 1894 sal_Bool ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const 1895 { 1896 // #i30830# changed behavior: 1897 // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows 1898 // below the last content cell 1899 1900 if ( nLastData == MAXROW ) 1901 { 1902 rLastRow = MAXROW; // can't look for attributes below MAXROW 1903 return sal_True; 1904 } 1905 1906 sal_Bool bFound = sal_False; 1907 1908 // loop backwards from the end instead of using Search, assuming that 1909 // there usually aren't many attributes below the last cell 1910 1911 SCSIZE nPos = nCount; 1912 while ( nPos > 0 && pData[nPos-1].nRow > nLastData ) 1913 { 1914 SCSIZE nEndPos = nPos - 1; 1915 SCSIZE nStartPos = nEndPos; // find range of visually equal formats 1916 while ( nStartPos > 0 && 1917 pData[nStartPos-1].nRow > nLastData && 1918 pData[nStartPos-1].pPattern->IsVisibleEqual(*pData[nStartPos].pPattern) ) 1919 --nStartPos; 1920 1921 SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos-1].nRow + 1 ) : 0; 1922 if ( nAttrStartRow <= nLastData ) 1923 nAttrStartRow = nLastData + 1; 1924 SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow; 1925 if ( nAttrSize >= SC_VISATTR_STOP ) 1926 { 1927 bFound = sal_False; // ignore this range and below 1928 } 1929 else if ( !bFound && pData[nEndPos].pPattern->IsVisible() ) 1930 { 1931 rLastRow = pData[nEndPos].nRow; 1932 bFound = sal_True; 1933 } 1934 1935 nPos = nStartPos; // look further from the top of the range 1936 } 1937 1938 return bFound; 1939 } 1940 1941 sal_Bool ScAttrArray::GetLastAttr( SCROW& rLastRow, SCROW nLastData ) const 1942 { 1943 if ( nLastData == MAXROW ) 1944 { 1945 rLastRow = MAXROW; 1946 return sal_True; 1947 } 1948 1949 sal_Bool bFound = sal_False; 1950 1951 // Loop backwards from the end instead of using Search, assuming that 1952 // there usually aren't many attributes below the last cell. 1953 SCSIZE nPos = nCount; 1954 while ( nPos > 0 && pData[nPos - 1].nRow > nLastData ) 1955 { 1956 SCSIZE nEndPos = nPos - 1; 1957 SCSIZE nStartPos = nEndPos; 1958 while ( nStartPos > 0 && pData[nStartPos - 1].nRow > nLastData && 1959 pData[nStartPos - 1].pPattern->IsEqual( *pData[nStartPos].pPattern ) ) 1960 --nStartPos; 1961 1962 SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos - 1].nRow + 1 ) : 0; 1963 if ( nAttrStartRow <= nLastData ) 1964 nAttrStartRow = nLastData + 1; 1965 SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow; 1966 if ( nAttrSize >= SC_VISATTR_STOP ) 1967 { 1968 bFound = sal_False; 1969 } 1970 else if ( !bFound ) 1971 { 1972 rLastRow = pData[nEndPos].nRow; 1973 bFound = sal_True; 1974 } 1975 1976 // look further from the top of the range. 1977 nPos = nStartPos; 1978 } 1979 1980 return bFound; 1981 } 1982 1983 1984 sal_Bool ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const 1985 { 1986 SCSIZE nIndex; 1987 Search( nStartRow, nIndex ); 1988 SCROW nThisStart = nStartRow; 1989 sal_Bool bFound = sal_False; 1990 while ( nIndex < nCount && nThisStart <= nEndRow && !bFound ) 1991 { 1992 if ( pData[nIndex].pPattern->IsVisible() ) 1993 bFound = sal_True; 1994 1995 nThisStart = pData[nIndex].nRow + 1; 1996 ++nIndex; 1997 } 1998 1999 return bFound; 2000 } 2001 2002 2003 sal_Bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther, 2004 SCROW nStartRow, SCROW nEndRow ) const 2005 { 2006 sal_Bool bEqual = sal_True; 2007 SCSIZE nThisPos = 0; 2008 SCSIZE nOtherPos = 0; 2009 if ( nStartRow > 0 ) 2010 { 2011 Search( nStartRow, nThisPos ); 2012 rOther.Search( nStartRow, nOtherPos ); 2013 } 2014 2015 while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual ) 2016 { 2017 SCROW nThisRow = pData[nThisPos].nRow; 2018 SCROW nOtherRow = rOther.pData[nOtherPos].nRow; 2019 const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern; 2020 const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern; 2021 bEqual = ( pThisPattern == pOtherPattern || 2022 pThisPattern->IsVisibleEqual(*pOtherPattern) ); 2023 2024 if ( nThisRow >= nOtherRow ) 2025 { 2026 if ( nOtherRow >= nEndRow ) break; 2027 ++nOtherPos; 2028 } 2029 if ( nThisRow <= nOtherRow ) 2030 { 2031 if ( nThisRow >= nEndRow ) break; 2032 ++nThisPos; 2033 } 2034 } 2035 2036 return bEqual; 2037 } 2038 2039 2040 sal_Bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const 2041 { 2042 //! mit IsVisibleEqual zusammenfassen? 2043 2044 sal_Bool bEqual = sal_True; 2045 SCSIZE nThisPos = 0; 2046 SCSIZE nOtherPos = 0; 2047 if ( nStartRow > 0 ) 2048 { 2049 Search( nStartRow, nThisPos ); 2050 rOther.Search( nStartRow, nOtherPos ); 2051 } 2052 2053 while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual ) 2054 { 2055 SCROW nThisRow = pData[nThisPos].nRow; 2056 SCROW nOtherRow = rOther.pData[nOtherPos].nRow; 2057 const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern; 2058 const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern; 2059 bEqual = ( pThisPattern == pOtherPattern ); 2060 2061 if ( nThisRow >= nOtherRow ) 2062 { 2063 if ( nOtherRow >= nEndRow ) break; 2064 ++nOtherPos; 2065 } 2066 if ( nThisRow <= nOtherRow ) 2067 { 2068 if ( nThisRow >= nEndRow ) break; 2069 ++nThisPos; 2070 } 2071 } 2072 2073 return bEqual; 2074 } 2075 2076 2077 sal_Bool ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const 2078 { 2079 // horizontal zusammengefasste duerfen nicht herausgeschoben werden 2080 // (ob die ganze Zusammenfassung betroffen ist, ist hier nicht zu erkennen) 2081 2082 sal_Bool bTest = sal_True; 2083 if (!IsEmpty()) 2084 { 2085 SCSIZE nIndex = 0; 2086 if ( nStartRow > 0 ) 2087 Search( nStartRow, nIndex ); 2088 2089 for ( ; nIndex < nCount; nIndex++ ) 2090 { 2091 if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern-> 2092 GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() ) 2093 { 2094 bTest = sal_False; // darf nicht herausgeschoben werden 2095 break; 2096 } 2097 if ( pData[nIndex].nRow >= nEndRow ) // Ende des Bereichs 2098 break; 2099 } 2100 } 2101 return bTest; 2102 } 2103 2104 2105 sal_Bool ScAttrArray::TestInsertRow( SCSIZE nSize ) const 2106 { 2107 // wenn die erste herausgeschobene Zeile vertikal ueberlappt ist, 2108 // wuerde eine kaputte Zusammenfassung uebrigbleiben 2109 2110 if (pData) 2111 { 2112 // MAXROW + 1 - nSize = erste herausgeschobene Zeile 2113 2114 SCSIZE nFirstLost = nCount-1; 2115 while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) ) 2116 --nFirstLost; 2117 2118 if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern-> 2119 GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() ) 2120 return sal_False; 2121 } 2122 2123 return sal_True; 2124 } 2125 2126 2127 void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize ) 2128 { 2129 if (!pData) 2130 return; 2131 2132 SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // Vorgaenger erweitern 2133 SCSIZE nIndex; 2134 Search( nSearch, nIndex ); 2135 2136 // ein gesetztes ScMergeAttr darf nicht ausgedehnt werden 2137 // (darum hinterher wieder loeschen) 2138 2139 sal_Bool bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged(); 2140 2141 SCSIZE nRemove = 0; 2142 SCSIZE i; 2143 for (i = nIndex; i < nCount-1; i++) 2144 { 2145 SCROW nNew = pData[i].nRow + nSize; 2146 if ( nNew >= MAXROW ) // Ende erreicht ? 2147 { 2148 nNew = MAXROW; 2149 if (!nRemove) 2150 nRemove = i+1; // folgende loeschen 2151 } 2152 pData[i].nRow = nNew; 2153 } 2154 2155 // muessen Eintraege am Ende geloescht werden? 2156 2157 if (nRemove && nRemove < nCount) 2158 DeleteRange( nRemove, nCount-1 ); 2159 2160 if (bDoMerge) // ausgedehntes ScMergeAttr wieder reparieren 2161 { 2162 //! ApplyAttr fuer Bereiche !!! 2163 2164 const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE ); 2165 for (SCSIZE nAdd=0; nAdd<nSize; nAdd++) 2166 pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef ); 2167 2168 // im eingefuegten Bereich ist nichts zusammengefasst 2169 } 2170 2171 // Don't duplicate the merge flags in the inserted row. 2172 // #i108488# SC_MF_SCENARIO has to be allowed. 2173 RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON ); 2174 } 2175 2176 2177 void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize ) 2178 { 2179 if (pData) 2180 { 2181 sal_Bool bFirst=sal_True; 2182 SCSIZE nStartIndex = 0; 2183 SCSIZE nEndIndex = 0; 2184 SCSIZE i; 2185 2186 for ( i = 0; i < nCount-1; i++) 2187 if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1)) 2188 { 2189 if (bFirst) 2190 { 2191 nStartIndex = i; 2192 bFirst = sal_False; 2193 } 2194 nEndIndex = i; 2195 } 2196 if (!bFirst) 2197 { 2198 SCROW nStart; 2199 if (nStartIndex==0) 2200 nStart = 0; 2201 else 2202 nStart = pData[nStartIndex-1].nRow + 1; 2203 2204 if (nStart < nStartRow) 2205 { 2206 pData[nStartIndex].nRow = nStartRow - 1; 2207 ++nStartIndex; 2208 } 2209 if (nEndIndex >= nStartIndex) 2210 { 2211 DeleteRange( nStartIndex, nEndIndex ); 2212 if (nStartIndex > 0) 2213 if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern ) 2214 DeleteRange( nStartIndex-1, nStartIndex-1 ); 2215 } 2216 } 2217 for (i = 0; i < nCount-1; i++) 2218 if (pData[i].nRow >= nStartRow) 2219 pData[i].nRow -= nSize; 2220 2221 // unten nicht Default-Pattern nachschieben, um Druckbereiche erkennen zu koennen 2222 // stattdessen nur Merge-Flags loeschen 2223 2224 RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO ); 2225 } 2226 } 2227 2228 2229 void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex ) 2230 { 2231 ScDocumentPool* pDocPool = pDocument->GetPool(); 2232 for (SCSIZE i = nStartIndex; i <= nEndIndex; i++) 2233 pDocPool->Remove(*pData[i].pPattern); 2234 2235 memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) ); 2236 nCount -= nEndIndex-nStartIndex+1; 2237 } 2238 2239 2240 void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow) 2241 { 2242 RemoveAreaMerge( nStartRow, nEndRow ); // von zusammengefassten auch die Flags loeschen 2243 2244 if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) ) 2245 SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() ); 2246 else 2247 DeleteAreaSafe( nStartRow, nEndRow ); // Merge-Flags stehenlassen 2248 } 2249 2250 2251 void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow) 2252 { 2253 const ScPatternAttr* pDefPattern = pDocument->GetDefPattern(); 2254 const ScPatternAttr* pOldPattern; 2255 2256 SCSIZE nIndex; 2257 SCROW nRow; 2258 SCROW nThisRow; 2259 2260 Search( nStartRow, nIndex ); 2261 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0; 2262 if (nThisRow < nStartRow) nThisRow = nStartRow; 2263 2264 while ( nThisRow <= nEndRow ) 2265 { 2266 pOldPattern = pData[nIndex].pPattern; 2267 2268 if ( pOldPattern->GetItemSet().Count() ) // harte Attribute ? 2269 { 2270 nRow = pData[nIndex].nRow; 2271 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow ); 2272 2273 ScPatternAttr aNewPattern(*pOldPattern); 2274 SfxItemSet& rSet = aNewPattern.GetItemSet(); 2275 for (sal_uInt16 nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++) 2276 if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG) 2277 rSet.ClearItem(nId); 2278 2279 if ( aNewPattern == *pDefPattern ) 2280 SetPatternArea( nThisRow, nAttrRow, pDefPattern, sal_False ); 2281 else 2282 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True ); 2283 2284 Search( nThisRow, nIndex ); // Daten wurden veraendert !!! 2285 } 2286 2287 ++nIndex; 2288 nThisRow = pData[nIndex-1].nRow+1; 2289 } 2290 } 2291 2292 // Verschieben innerhalb eines Dokuments 2293 2294 void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray) 2295 { 2296 SCROW nStart = nStartRow; 2297 for (SCSIZE i = 0; i < nCount; i++) 2298 { 2299 if ((pData[i].nRow >= nStartRow) && ((i==0) ? sal_True : pData[i-1].nRow < nEndRow)) 2300 { 2301 // Kopieren (bPutToPool=sal_True) 2302 rAttrArray.SetPatternArea( nStart, Min( (SCROW)pData[i].nRow, (SCROW)nEndRow ), 2303 pData[i].pPattern, sal_True ); 2304 } 2305 nStart = Max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) ); 2306 } 2307 DeleteArea(nStartRow, nEndRow); 2308 } 2309 2310 2311 // Kopieren zwischen Dokumenten (Clipboard) 2312 2313 void ScAttrArray::CopyArea( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray, 2314 sal_Int16 nStripFlags ) 2315 { 2316 nStartRow -= nDy; // Source 2317 nEndRow -= nDy; 2318 2319 SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0); 2320 SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW); 2321 2322 ScDocumentPool* pSourceDocPool = pDocument->GetPool(); 2323 ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool(); 2324 sal_Bool bSamePool = (pSourceDocPool==pDestDocPool); 2325 2326 for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++) 2327 { 2328 if (pData[i].nRow >= nStartRow) 2329 { 2330 const ScPatternAttr* pOldPattern = pData[i].pPattern; 2331 const ScPatternAttr* pNewPattern; 2332 2333 if (IsDefaultItem( pOldPattern )) 2334 { 2335 // am Default muss nichts veraendert werden 2336 2337 pNewPattern = (const ScPatternAttr*) 2338 &pDestDocPool->GetDefaultItem( ATTR_PATTERN ); 2339 } 2340 else if ( nStripFlags ) 2341 { 2342 ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern ); 2343 sal_Int16 nNewFlags = 0; 2344 if ( nStripFlags != SC_MF_ALL ) 2345 nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)). 2346 GetValue() & ~nStripFlags; 2347 2348 if ( nNewFlags ) 2349 pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) ); 2350 else 2351 pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG ); 2352 2353 if (bSamePool) 2354 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern); 2355 else 2356 pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument ); 2357 delete pTmpPattern; 2358 } 2359 else 2360 { 2361 if (bSamePool) 2362 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern); 2363 else 2364 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument ); 2365 } 2366 2367 rAttrArray.SetPatternArea(nDestStart, 2368 Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern); 2369 } 2370 2371 // when pasting from clipboard and skipping filtered rows, the adjusted end position 2372 // can be negative 2373 nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1)); 2374 } 2375 } 2376 2377 // Flags stehenlassen 2378 //! mit CopyArea zusammenfassen !!! 2379 2380 void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray ) 2381 { 2382 nStartRow -= nDy; // Source 2383 nEndRow -= nDy; 2384 2385 SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0); 2386 SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW); 2387 2388 if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) ) 2389 { 2390 CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray ); 2391 return; 2392 } 2393 2394 ScDocumentPool* pSourceDocPool = pDocument->GetPool(); 2395 ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool(); 2396 sal_Bool bSamePool = (pSourceDocPool==pDestDocPool); 2397 2398 for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++) 2399 { 2400 if (pData[i].nRow >= nStartRow) 2401 { 2402 const ScPatternAttr* pOldPattern = pData[i].pPattern; 2403 const ScPatternAttr* pNewPattern; 2404 2405 if (bSamePool) 2406 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern); 2407 else 2408 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument ); 2409 2410 rAttrArray.SetPatternAreaSafe(nDestStart, 2411 Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, sal_False); 2412 } 2413 2414 // when pasting from clipboard and skipping filtered rows, the adjusted end position 2415 // can be negative 2416 nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1)); 2417 } 2418 } 2419 2420 2421 SCsROW ScAttrArray::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle, 2422 sal_Bool bUp, ScMarkArray* pMarkArray ) 2423 { 2424 sal_Bool bFound = sal_False; 2425 2426 if (pMarkArray) 2427 { 2428 nRow = pMarkArray->GetNextMarked( nRow, bUp ); 2429 if (!VALIDROW(nRow)) 2430 return nRow; 2431 } 2432 2433 SCSIZE nIndex; 2434 Search(nRow, nIndex); 2435 const ScPatternAttr* pPattern = pData[nIndex].pPattern; 2436 2437 while (nIndex < nCount && !bFound) 2438 { 2439 if (pPattern->GetStyleSheet() == pSearchStyle) 2440 { 2441 if (pMarkArray) 2442 { 2443 nRow = pMarkArray->GetNextMarked( nRow, bUp ); 2444 SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0; 2445 if (nRow >= nStart && nRow <= pData[nIndex].nRow) 2446 bFound = sal_True; 2447 } 2448 else 2449 bFound = sal_True; 2450 } 2451 2452 if (!bFound) 2453 { 2454 if (bUp) 2455 { 2456 if (nIndex==0) 2457 { 2458 nIndex = nCount; 2459 nRow = -1; 2460 } 2461 else 2462 { 2463 --nIndex; 2464 nRow = pData[nIndex].nRow; 2465 pPattern = pData[nIndex].pPattern; 2466 } 2467 } 2468 else 2469 { 2470 nRow = pData[nIndex].nRow+1; 2471 ++nIndex; 2472 if (nIndex<nCount) 2473 pPattern = pData[nIndex].pPattern; 2474 } 2475 } 2476 } 2477 2478 DBG_ASSERT( bFound || !ValidRow(nRow), "interner Fehler in ScAttrArray::SearchStyle" ); 2479 2480 return nRow; 2481 } 2482 2483 2484 sal_Bool ScAttrArray::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow, 2485 const ScStyleSheet* pSearchStyle, sal_Bool bUp, ScMarkArray* pMarkArray ) 2486 { 2487 SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray ); 2488 if (VALIDROW(nStartRow)) 2489 { 2490 SCSIZE nIndex; 2491 Search(nStartRow,nIndex); 2492 2493 rRow = nStartRow; 2494 if (bUp) 2495 { 2496 if (nIndex>0) 2497 rEndRow = pData[nIndex-1].nRow + 1; 2498 else 2499 rEndRow = 0; 2500 if (pMarkArray) 2501 { 2502 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_True ); 2503 if (nMarkEnd>rEndRow) 2504 rEndRow = nMarkEnd; 2505 } 2506 } 2507 else 2508 { 2509 rEndRow = pData[nIndex].nRow; 2510 if (pMarkArray) 2511 { 2512 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, sal_False ); 2513 if (nMarkEnd<rEndRow) 2514 rEndRow = nMarkEnd; 2515 } 2516 } 2517 2518 return sal_True; 2519 } 2520 else 2521 return sal_False; 2522 } 2523 2524 //------------------------------------------------------------------------ 2525 // 2526 // Laden / Speichern 2527 // 2528 2529 2530 #if 0 2531 void ScAttrArray::Save( SvStream& /* rStream */ ) const 2532 { 2533 #if SC_ROWLIMIT_STREAM_ACCESS 2534 #error address types changed! 2535 ScWriteHeader aHdr( rStream, 8 ); 2536 2537 ScDocumentPool* pDocPool = pDocument->GetPool(); 2538 2539 sal_uInt16 nSaveCount = nCount; 2540 SCROW nSaveMaxRow = pDocument->GetSrcMaxRow(); 2541 if ( nSaveMaxRow != MAXROW ) 2542 { 2543 if ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow ) 2544 { 2545 pDocument->SetLostData(); // Warnung ausgeben 2546 do 2547 --nSaveCount; 2548 while ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow ); 2549 } 2550 } 2551 2552 rStream << nSaveCount; 2553 2554 const SfxPoolItem* pItem; 2555 for (SCSIZE i=0; i<nSaveCount; i++) 2556 { 2557 rStream << Min( pData[i].nRow, nSaveMaxRow ); 2558 2559 const ScPatternAttr* pPattern = pData[i].pPattern; 2560 pDocPool->StoreSurrogate( rStream, pPattern ); 2561 2562 // sal_False, weil ATTR_CONDITIONAL (noch) nicht in Vorlagen: 2563 if (pPattern->GetItemSet().GetItemState(ATTR_CONDITIONAL,sal_False,&pItem) == SFX_ITEM_SET) 2564 pDocument->SetConditionalUsed( ((const SfxUInt32Item*)pItem)->GetValue() ); 2565 2566 if (pPattern->GetItemSet().GetItemState(ATTR_VALIDDATA,sal_False,&pItem) == SFX_ITEM_SET) 2567 pDocument->SetValidationUsed( ((const SfxUInt32Item*)pItem)->GetValue() ); 2568 } 2569 #endif // SC_ROWLIMIT_STREAM_ACCESS 2570 } 2571 2572 2573 void ScAttrArray::Load( SvStream& /* rStream */ ) 2574 { 2575 #if SC_ROWLIMIT_STREAM_ACCESS 2576 #error address types changed! 2577 ScDocumentPool* pDocPool = pDocument->GetPool(); 2578 2579 ScReadHeader aHdr( rStream ); 2580 2581 sal_uInt16 nNewCount; 2582 rStream >> nNewCount; 2583 if ( nNewCount > MAXROW+1 ) // wuerde das Array zu gross? 2584 { 2585 pDocument->SetLostData(); 2586 rStream.SetError( SVSTREAM_FILEFORMAT_ERROR ); 2587 return; 2588 } 2589 2590 Reset( pDocument->GetDefPattern(), sal_False ); // loeschen 2591 pData = new ScAttrEntry[nNewCount]; // neu anlegen 2592 for (SCSIZE i=0; i<nNewCount; i++) 2593 { 2594 rStream >> pData[i].nRow; 2595 2596 sal_uInt16 nWhich = ATTR_PATTERN; 2597 const ScPatternAttr* pNewPattern = (const ScPatternAttr*) 2598 pDocPool->LoadSurrogate( rStream, nWhich, ATTR_PATTERN ); 2599 if (!pNewPattern) 2600 { 2601 // da is was schiefgelaufen 2602 DBG_ERROR("ScAttrArray::Load: Surrogat nicht im Pool"); 2603 pNewPattern = pDocument->GetDefPattern(); 2604 } 2605 ScDocumentPool::CheckRef( *pNewPattern ); 2606 pData[i].pPattern = pNewPattern; 2607 2608 // LoadSurrogate erhoeht auch die Ref 2609 } 2610 nCount = nLimit = nNewCount; 2611 2612 if ( nCount > 1 && pData[nCount-2].nRow >= MAXROW ) // faengt ein Attribut hinter MAXROW an? 2613 { 2614 pDocument->SetLostData(); 2615 rStream.SetError( SVSTREAM_FILEFORMAT_ERROR ); 2616 return; 2617 } 2618 2619 if ( pDocument->GetSrcMaxRow() != MAXROW ) // Ende anpassen? 2620 { 2621 // Ende immer auf MAXROW umsetzen (nur auf 32 Bit) 2622 2623 DBG_ASSERT( pData[nCount-1].nRow == pDocument->GetSrcMaxRow(), "Attribut-Ende ?!?" ); 2624 pData[nCount-1].nRow = MAXROW; 2625 } 2626 #endif // SC_ROWLIMIT_STREAM_ACCESS 2627 } 2628 #endif 2629 2630 2631 //UNUSED2008-05 void ScAttrArray::ConvertFontsAfterLoad() 2632 //UNUSED2008-05 { 2633 //UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter; 2634 //UNUSED2008-05 const sal_uLong nFlags = FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS; 2635 //UNUSED2008-05 SCSIZE nIndex = 0; 2636 //UNUSED2008-05 SCROW nThisRow = 0; 2637 //UNUSED2008-05 2638 //UNUSED2008-05 while ( nThisRow <= MAXROW ) 2639 //UNUSED2008-05 { 2640 //UNUSED2008-05 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern; 2641 //UNUSED2008-05 const SfxPoolItem* pItem; 2642 //UNUSED2008-05 if( pOldPattern->GetItemSet().GetItemState( ATTR_FONT, sal_False, &pItem ) == SFX_ITEM_SET ) 2643 //UNUSED2008-05 { 2644 //UNUSED2008-05 const SvxFontItem* pFontItem = (const SvxFontItem*) pItem; 2645 //UNUSED2008-05 const String& rOldName = pFontItem->GetFamilyName(); 2646 //UNUSED2008-05 xFontConverter = CreateFontToSubsFontConverter( rOldName, nFlags ); 2647 //UNUSED2008-05 if ( xFontConverter ) 2648 //UNUSED2008-05 { 2649 //UNUSED2008-05 String aNewName( GetFontToSubsFontName( xFontConverter ) ); 2650 //UNUSED2008-05 if ( aNewName != rOldName ) 2651 //UNUSED2008-05 { 2652 //UNUSED2008-05 SCROW nAttrRow = pData[nIndex].nRow; 2653 //UNUSED2008-05 SvxFontItem aNewItem( pFontItem->GetFamily(), aNewName, 2654 //UNUSED2008-05 pFontItem->GetStyleName(), pFontItem->GetPitch(), 2655 //UNUSED2008-05 RTL_TEXTENCODING_DONTKNOW, ATTR_FONT ); 2656 //UNUSED2008-05 ScPatternAttr aNewPattern( *pOldPattern ); 2657 //UNUSED2008-05 aNewPattern.GetItemSet().Put( aNewItem ); 2658 //UNUSED2008-05 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, sal_True ); 2659 //UNUSED2008-05 Search( nThisRow, nIndex ); //! data changed 2660 //UNUSED2008-05 } 2661 //UNUSED2008-05 } 2662 //UNUSED2008-05 } 2663 //UNUSED2008-05 ++nIndex; 2664 //UNUSED2008-05 nThisRow = pData[nIndex-1].nRow+1; 2665 //UNUSED2008-05 } 2666 //UNUSED2008-05 } 2667 2668 SCSIZE ScAttrArray::Count( SCROW nStartRow, SCROW nEndRow ) 2669 { 2670 SCSIZE nIndex1, nIndex2; 2671 2672 if( !Search( nStartRow, nIndex1 ) ) 2673 return 0; 2674 2675 if( !Search( nEndRow, nIndex2 ) ) 2676 nIndex2 = this->nCount - 1; 2677 2678 return nIndex2 - nIndex1 + 1; 2679 } 2680