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