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