update dev300-m58
[ooovba.git] / sc / source / core / data / attarray.cxx
blob3807adeb67ddd1b0521c906e51e02562567b9db8
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: attarray.cxx,v $
10 * $Revision: 1.25.32.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
36 //------------------------------------------------------------------------
38 #include "scitems.hxx"
39 #include <svx/algitem.hxx>
40 #include <svx/boxitem.hxx>
41 #include <svx/bolnitem.hxx>
42 #include <svx/frmdiritem.hxx>
43 #include <svx/shaditem.hxx>
44 #include <svx/editobj.hxx>
45 #include <svtools/poolcach.hxx>
46 #include <svx/fontitem.hxx>
47 #include <vcl/fontcvt.hxx>
49 #include "attarray.hxx"
50 #include "global.hxx"
51 #include "document.hxx"
52 #include "docpool.hxx"
53 #include "patattr.hxx"
54 #include "stlsheet.hxx"
55 #include "stlpool.hxx"
56 #include "markarr.hxx"
57 #include "rechead.hxx"
58 #include "globstr.hrc"
59 #include "cell.hxx"
60 #include "segmenttree.hxx"
62 #undef DBG_INVALIDATE
63 #define DBGOUTPUT(s) \
64 DBG_ERROR( String("Invalidate ") + String(s) + String(": ") \
65 + String(nCol) + String('/') + String(aAdrStart.Row()) + String('/') + String(nTab) \
66 + String(" bis ") \
67 + String(nCol) + String('/') + String(aAdrEnd.Row()) + String('/') + String(nTab) \
70 // STATIC DATA -----------------------------------------------------------
73 //------------------------------------------------------------------------
75 ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) :
76 nCol( nNewCol ),
77 nTab( nNewTab ),
78 pDocument( pDoc )
80 nCount = nLimit = 1;
81 pData = new ScAttrEntry[1];
82 if (pData)
84 pData[0].nRow = MAXROW;
85 pData[0].pPattern = pDocument->GetDefPattern(); // ohne Put !!!
89 //------------------------------------------------------------------------
91 ScAttrArray::~ScAttrArray()
93 #ifdef DBG_UTIL
94 TestData();
95 #endif
97 if (pData)
99 ScDocumentPool* pDocPool = pDocument->GetPool();
100 for (SCSIZE i=0; i<nCount; i++)
101 pDocPool->Remove(*pData[i].pPattern);
103 delete[] pData;
107 //------------------------------------------------------------------------
108 #ifdef DBG_UTIL
109 void ScAttrArray::TestData() const
112 USHORT nErr = 0;
113 if (pData)
115 SCSIZE nPos;
116 for (nPos=0; nPos<nCount; nPos++)
118 if (nPos > 0)
119 if (pData[nPos].pPattern == pData[nPos-1].pPattern || pData[nPos].nRow <= pData[nPos-1].nRow)
120 ++nErr;
121 if (pData[nPos].pPattern->Which() != ATTR_PATTERN)
122 ++nErr;
124 if ( nPos && pData[nPos-1].nRow != MAXROW )
125 ++nErr;
127 if (nErr)
129 ByteString aMsg = ByteString::CreateFromInt32(nErr);
130 aMsg += " errors in attribute array, column ";
131 aMsg += ByteString::CreateFromInt32(nCol);
132 DBG_ERROR( aMsg.GetBuffer() );
135 #endif
137 //------------------------------------------------------------------------
139 void ScAttrArray::Reset( const ScPatternAttr* pPattern, BOOL bAlloc )
141 if (pData)
143 ScDocumentPool* pDocPool = pDocument->GetPool();
144 const ScPatternAttr* pOldPattern;
145 ScAddress aAdrStart( nCol, 0, nTab );
146 ScAddress aAdrEnd ( nCol, 0, nTab );
148 for (SCSIZE i=0; i<nCount; i++)
150 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
151 pOldPattern = pData[i].pPattern;
152 BOOL bNumFormatChanged;
153 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
154 pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
156 aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
157 aAdrEnd .SetRow( pData[i].nRow );
158 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
159 #ifdef DBG_INVALIDATE
160 DBGOUTPUT("Reset");
161 #endif
163 // bedingtes Format gesetzt oder geloescht?
164 if ( &pPattern->GetItem(ATTR_CONDITIONAL) != &pOldPattern->GetItem(ATTR_CONDITIONAL) )
166 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
167 pOldPattern->GetItem(ATTR_CONDITIONAL)).GetValue() );
168 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
169 pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() );
171 pDocPool->Remove(*pOldPattern);
173 delete[] pData;
175 if (pDocument->IsStreamValid(nTab))
176 pDocument->SetStreamValid(nTab, FALSE);
178 if (bAlloc)
180 nCount = nLimit = 1;
181 pData = new ScAttrEntry[1];
182 if (pData)
184 ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern);
185 pData[0].nRow = MAXROW;
186 pData[0].pPattern = pNewPattern;
189 else
191 nCount = nLimit = 0;
192 pData = NULL; // muss sofort wieder belegt werden !
198 BOOL ScAttrArray::Concat(SCSIZE nPos)
200 BOOL bRet = FALSE;
201 if (pData && (nPos < nCount))
203 if (nPos > 0)
205 if (pData[nPos - 1].pPattern == pData[nPos].pPattern)
207 pData[nPos - 1].nRow = pData[nPos].nRow;
208 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
209 memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry));
210 pData[nCount - 1].pPattern = NULL;
211 pData[nCount - 1].nRow = 0;
212 nCount--;
213 nPos--;
214 bRet = TRUE;
217 if (nPos + 1 < nCount)
219 if (pData[nPos + 1].pPattern == pData[nPos].pPattern)
221 pData[nPos].nRow = pData[nPos + 1].nRow;
222 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
223 memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry));
224 pData[nCount - 1].pPattern = NULL;
225 pData[nCount - 1].nRow = 0;
226 nCount--;
227 bRet = TRUE;
231 return bRet;
234 //------------------------------------------------------------------------
236 BOOL ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
238 long nLo = 0;
239 long nHi = static_cast<long>(nCount) - 1;
240 long nStartRow = 0;
241 long nEndRow = 0;
242 long i = 0;
243 BOOL bFound = (nCount == 1);
244 if (pData)
246 while ( !bFound && nLo <= nHi )
248 i = (nLo + nHi) / 2;
249 if (i > 0)
250 nStartRow = (long) pData[i - 1].nRow;
251 else
252 nStartRow = -1;
253 nEndRow = (long) pData[i].nRow;
254 if (nEndRow < (long) nRow)
255 nLo = ++i;
256 else
257 if (nStartRow >= (long) nRow)
258 nHi = --i;
259 else
260 bFound = TRUE;
263 else
264 bFound = FALSE;
266 if (bFound)
267 nIndex=(SCSIZE)i;
268 else
269 nIndex=0;
270 return bFound;
274 const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
276 SCSIZE i;
277 if (Search( nRow, i ))
278 return pData[i].pPattern;
279 else
280 return NULL;
284 const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
285 SCROW& rEndRow, SCROW nRow ) const
287 SCSIZE nIndex;
288 if ( Search( nRow, nIndex ) )
290 if ( nIndex > 0 )
291 rStartRow = pData[nIndex-1].nRow + 1;
292 else
293 rStartRow = 0;
294 rEndRow = pData[nIndex].nRow;
295 return pData[nIndex].pPattern;
297 return NULL;
300 //------------------------------------------------------------------------
302 void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, BOOL bPutToPool )
304 SetPatternArea( nRow, nRow, pPattern, bPutToPool );
307 void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
308 const ScPatternAttr* pPattern, ScEditDataArray* pDataArray )
310 for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
312 ScBaseCell* pCell;
313 pDocument->GetCell(nCol, nRow, nTab, pCell);
314 if (pCell && pCell->GetCellType() == CELLTYPE_EDIT)
316 EditTextObject* pOldData = NULL;
317 ScEditCell* pEditCell = static_cast<ScEditCell*>(pCell);
318 if (pDataArray)
319 pOldData = pEditCell->GetData()->Clone();
320 pEditCell->RemoveCharAttribs(*pPattern);
321 if (pDataArray)
323 EditTextObject* pNewData = pEditCell->GetData()->Clone();
324 pDataArray->AddItem(nTab, nCol, nRow, pOldData, pNewData);
330 void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern,
331 BOOL bPutToPool, ScEditDataArray* pDataArray )
333 if (ValidRow(nStartRow) && ValidRow(nEndRow))
335 if (bPutToPool)
336 pPattern = (const ScPatternAttr*) &pDocument->GetPool()->Put(*pPattern);
338 if ((nStartRow == 0) && (nEndRow == MAXROW))
339 Reset(pPattern);
340 else
342 SCSIZE nNeeded = nCount + 2;
343 if ( nLimit < nNeeded )
345 nLimit += SC_ATTRARRAY_DELTA;
346 if ( nLimit < nNeeded )
347 nLimit = nNeeded;
348 ScAttrEntry* pNewData = new ScAttrEntry[nLimit];
349 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
350 delete[] pData;
351 pData = pNewData;
354 ScAddress aAdrStart( nCol, 0, nTab );
355 ScAddress aAdrEnd ( nCol, 0, nTab );
357 SCSIZE ni = 0; // number of entries in beginning
358 SCSIZE nx = 0; // track position
359 SCROW ns = 0; // start row of track position
360 if ( nStartRow > 0 )
362 // skip beginning
363 SCSIZE nIndex;
364 Search( nStartRow, nIndex );
365 ni = nIndex;
367 if ( ni > 0 )
369 nx = ni;
370 ns = pData[ni-1].nRow+1;
374 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
375 // oder bedingte Formate neu gesetzt oder geloescht werden
376 while ( ns <= nEndRow )
378 const SfxItemSet& rNewSet = pPattern->GetItemSet();
379 const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
381 BOOL bNumFormatChanged;
382 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
383 rNewSet, rOldSet ) )
385 aAdrStart.SetRow( Max(nStartRow,ns) );
386 aAdrEnd .SetRow( Min(nEndRow,pData[nx].nRow) );
387 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
388 #ifdef DBG_INVALIDATE
389 DBGOUTPUT("SetPatternArea");
390 #endif
392 if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
394 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
395 rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
396 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
397 rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
399 ns = pData[nx].nRow + 1;
400 nx++;
403 // continue modifying data array
405 SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert)
406 BOOL bCombined = FALSE;
407 BOOL bSplit = FALSE;
408 if ( nStartRow > 0 )
410 nInsert = MAXROWCOUNT;
411 if ( pData[ni].pPattern != pPattern )
413 if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
414 { // may be a split or a simple insert or just a shrink,
415 // row adjustment is done further down
416 if ( pData[ni].nRow > nEndRow )
417 bSplit = TRUE;
418 ni++;
419 nInsert = ni;
421 else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
422 nInsert = ni;
424 if ( ni > 0 && pData[ni-1].pPattern == pPattern )
425 { // combine
426 pData[ni-1].nRow = nEndRow;
427 nInsert = MAXROWCOUNT;
428 bCombined = TRUE;
431 else
432 nInsert = 0;
434 SCSIZE nj = ni; // stop position of range to replace
435 while ( nj < nCount && pData[nj].nRow <= nEndRow )
436 nj++;
437 if ( !bSplit )
439 if ( nj < nCount && pData[nj].pPattern == pPattern )
440 { // combine
441 if ( ni > 0 )
443 if ( pData[ni-1].pPattern == pPattern )
444 { // adjacent entries
445 pData[ni-1].nRow = pData[nj].nRow;
446 nj++;
448 else if ( ni == nInsert )
449 pData[ni-1].nRow = nStartRow - 1; // shrink
451 nInsert = MAXROWCOUNT;
452 bCombined = TRUE;
454 else if ( ni > 0 && ni == nInsert )
455 pData[ni-1].nRow = nStartRow - 1; // shrink
457 ScDocumentPool* pDocPool = pDocument->GetPool();
458 if ( bSplit )
459 { // duplicate splitted entry in pool
460 pDocPool->Put( *pData[ni-1].pPattern );
462 if ( ni < nj )
463 { // remove middle entries
464 for ( SCSIZE nk=ni; nk<nj; nk++)
465 { // remove entries from pool
466 pDocPool->Remove( *pData[nk].pPattern );
468 if ( !bCombined )
469 { // replace one entry
470 pData[ni].nRow = nEndRow;
471 pData[ni].pPattern = pPattern;
472 ni++;
473 nInsert = MAXROWCOUNT;
475 if ( ni < nj )
476 { // remove entries
477 memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
478 nCount -= nj - ni;
482 if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
483 { // insert or append new entry
484 if ( nInsert <= nCount )
486 if ( !bSplit )
487 memmove( pData + nInsert + 1, pData + nInsert,
488 (nCount - nInsert) * sizeof(ScAttrEntry) );
489 else
491 memmove( pData + nInsert + 2, pData + nInsert,
492 (nCount - nInsert) * sizeof(ScAttrEntry) );
493 pData[nInsert+1] = pData[nInsert-1];
494 nCount++;
497 if ( nInsert )
498 pData[nInsert-1].nRow = nStartRow - 1;
499 pData[nInsert].nRow = nEndRow;
500 pData[nInsert].pPattern = pPattern;
502 // Remove character attributes from these cells if the pattern
503 // is applied during normal session. We don't want to do this
504 // while importing document.
505 if (!pDocument->IsLoadingMedium())
506 RemoveCellCharAttribs(nStartRow, nEndRow, pPattern ,pDataArray);
508 nCount++;
511 if (pDocument->IsStreamValid(nTab))
512 pDocument->SetStreamValid(nTab, FALSE);
515 // InfoBox(0, String(nCount) + String(" Eintraege") ).Execute();
517 #ifdef DBG_UTIL
518 TestData();
519 #endif
523 void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
525 if (ValidRow(nStartRow) && ValidRow(nEndRow))
527 SCSIZE nPos;
528 SCROW nStart=0;
529 if (!Search( nStartRow, nPos ))
531 DBG_ERROR("Search-Fehler");
532 return;
535 ScAddress aAdrStart( nCol, 0, nTab );
536 ScAddress aAdrEnd ( nCol, 0, nTab );
540 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
541 ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
542 pNewPattern->SetStyleSheet(pStyle);
543 SCROW nY1 = nStart;
544 SCROW nY2 = pData[nPos].nRow;
545 nStart = pData[nPos].nRow + 1;
547 if ( *pNewPattern == *pOldPattern )
549 // keep the original pattern (might be default)
550 // pNewPattern is deleted below
551 nPos++;
553 else if ( nY1 < nStartRow || nY2 > nEndRow )
555 if (nY1 < nStartRow) nY1=nStartRow;
556 if (nY2 > nEndRow) nY2=nEndRow;
557 SetPatternArea( nY1, nY2, pNewPattern, TRUE );
558 Search( nStart, nPos );
560 else
562 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
563 // bedingte Formate in Vorlagen gibt es (noch) nicht
565 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
566 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
568 BOOL bNumFormatChanged;
569 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
570 rNewSet, rOldSet ) )
572 aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
573 aAdrEnd .SetRow( pData[nPos].nRow );
574 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
575 #ifdef DBG_INVALIDATE
576 DBGOUTPUT("ApplyStyleArea");
577 #endif
580 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
581 pData[nPos].pPattern = (const ScPatternAttr*)
582 &pDocument->GetPool()->Put(*pNewPattern);
583 if (Concat(nPos))
584 Search(nStart, nPos);
585 else
586 nPos++;
588 delete pNewPattern;
590 while ((nStart <= nEndRow) && (nPos < nCount));
592 if (pDocument->IsStreamValid(nTab))
593 pDocument->SetStreamValid(nTab, FALSE);
596 #ifdef DBG_UTIL
597 TestData();
598 #endif
602 // const wird weggecastet, weil es sonst
603 // zu ineffizient/kompliziert wird!
604 #define SET_LINECOLOR(dest,c) \
605 if ((dest)) \
607 ((SvxBorderLine*)(dest))->SetColor((c)); \
610 #define SET_LINE(dest,src) \
611 if ((dest)) \
613 SvxBorderLine* pCast = (SvxBorderLine*)(dest); \
614 pCast->SetOutWidth((src)->GetOutWidth()); \
615 pCast->SetInWidth ((src)->GetInWidth()); \
616 pCast->SetDistance((src)->GetDistance()); \
619 void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
620 const SvxBorderLine* pLine, BOOL bColorOnly )
622 if ( bColorOnly && !pLine )
623 return;
625 if (ValidRow(nStartRow) && ValidRow(nEndRow))
627 SCSIZE nPos;
628 SCROW nStart=0;
629 if (!Search( nStartRow, nPos ))
631 DBG_ERROR("Search-Fehler");
632 return;
637 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
638 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
639 const SfxPoolItem* pBoxItem = 0;
640 SfxItemState eState = rOldSet.GetItemState( ATTR_BORDER, TRUE, &pBoxItem );
641 const SfxPoolItem* pTLBRItem = 0;
642 SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, TRUE, &pTLBRItem );
643 const SfxPoolItem* pBLTRItem = 0;
644 SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, TRUE, &pBLTRItem );
646 if ( (SFX_ITEM_SET == eState) || (SFX_ITEM_SET == eTLBRState) || (SFX_ITEM_SET == eBLTRState) )
648 ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
649 SfxItemSet& rNewSet = pNewPattern->GetItemSet();
650 SCROW nY1 = nStart;
651 SCROW nY2 = pData[nPos].nRow;
653 SvxBoxItem* pNewBoxItem = pBoxItem ? (SvxBoxItem*)pBoxItem->Clone() : 0;
654 SvxLineItem* pNewTLBRItem = pTLBRItem ? (SvxLineItem*)pTLBRItem->Clone() : 0;
655 SvxLineItem* pNewBLTRItem = pBLTRItem ? (SvxLineItem*)pBLTRItem->Clone() : 0;
657 // Linienattribute holen und mit Parametern aktualisieren
659 if ( !pLine )
661 if( pNewBoxItem )
663 if ( pNewBoxItem->GetTop() ) pNewBoxItem->SetLine( NULL, BOX_LINE_TOP );
664 if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, BOX_LINE_BOTTOM );
665 if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( NULL, BOX_LINE_LEFT );
666 if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( NULL, BOX_LINE_RIGHT );
668 if( pNewTLBRItem && pNewTLBRItem->GetLine() )
669 pNewTLBRItem->SetLine( 0 );
670 if( pNewBLTRItem && pNewBLTRItem->GetLine() )
671 pNewBLTRItem->SetLine( 0 );
673 else
675 if ( bColorOnly )
677 Color aColor( pLine->GetColor() );
678 if( pNewBoxItem )
680 SET_LINECOLOR( pNewBoxItem->GetTop(), aColor );
681 SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor );
682 SET_LINECOLOR( pNewBoxItem->GetLeft(), aColor );
683 SET_LINECOLOR( pNewBoxItem->GetRight(), aColor );
685 if( pNewTLBRItem )
686 SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor );
687 if( pNewBLTRItem )
688 SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor );
690 else
692 if( pNewBoxItem )
694 SET_LINE( pNewBoxItem->GetTop(), pLine );
695 SET_LINE( pNewBoxItem->GetBottom(), pLine );
696 SET_LINE( pNewBoxItem->GetLeft(), pLine );
697 SET_LINE( pNewBoxItem->GetRight(), pLine );
699 if( pNewTLBRItem )
700 SET_LINE( pNewTLBRItem->GetLine(), pLine );
701 if( pNewBLTRItem )
702 SET_LINE( pNewBLTRItem->GetLine(), pLine );
705 if( pNewBoxItem ) rNewSet.Put( *pNewBoxItem );
706 if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem );
707 if( pNewBLTRItem ) rNewSet.Put( *pNewBLTRItem );
709 nStart = pData[nPos].nRow + 1;
711 if ( nY1 < nStartRow || nY2 > nEndRow )
713 if (nY1 < nStartRow) nY1=nStartRow;
714 if (nY2 > nEndRow) nY2=nEndRow;
715 SetPatternArea( nY1, nY2, pNewPattern, TRUE );
716 Search( nStart, nPos );
718 else
720 //! aus Pool loeschen?
721 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
722 pData[nPos].pPattern = (const ScPatternAttr*)
723 &pDocument->GetPool()->Put(*pNewPattern);
725 if (Concat(nPos))
726 Search(nStart, nPos);
727 else
728 nPos++;
730 delete pNewBoxItem;
731 delete pNewTLBRItem;
732 delete pNewBLTRItem;
733 delete pNewPattern;
735 else
737 nStart = pData[nPos].nRow + 1;
738 nPos++;
741 while ((nStart <= nEndRow) && (nPos < nCount));
745 #undef SET_LINECOLOR
746 #undef SET_LINE
749 void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, ScEditDataArray* pDataArray )
751 #ifdef DBG_UTIL
752 TestData();
753 #endif
755 if (ValidRow(nStartRow) && ValidRow(nEndRow))
757 SCSIZE nPos;
758 SCROW nStart=0;
759 if (!Search( nStartRow, nPos ))
761 DBG_ERROR("Search-Fehler");
762 return;
765 ScAddress aAdrStart( nCol, 0, nTab );
766 ScAddress aAdrEnd ( nCol, 0, nTab );
770 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
771 const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pCache->ApplyTo( *pOldPattern, TRUE );
772 ScDocumentPool::CheckRef( *pOldPattern );
773 ScDocumentPool::CheckRef( *pNewPattern );
774 if (pNewPattern != pOldPattern)
776 SCROW nY1 = nStart;
777 SCROW nY2 = pData[nPos].nRow;
778 nStart = pData[nPos].nRow + 1;
780 if ( nY1 < nStartRow || nY2 > nEndRow )
782 if (nY1 < nStartRow) nY1=nStartRow;
783 if (nY2 > nEndRow) nY2=nEndRow;
784 SetPatternArea( nY1, nY2, pNewPattern, false, pDataArray );
785 Search( nStart, nPos );
787 else
789 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
791 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
792 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
794 BOOL bNumFormatChanged;
795 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
796 rNewSet, rOldSet ) )
798 aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
799 aAdrEnd .SetRow( pData[nPos].nRow );
800 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
801 #ifdef DBG_INVALIDATE
802 DBGOUTPUT("ApplyCacheArea");
803 #endif
806 // bedingte Formate neu gesetzt oder geloescht ?
808 if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
810 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
811 rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
812 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
813 rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
816 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
817 pData[nPos].pPattern = pNewPattern;
818 if (Concat(nPos))
819 Search(nStart, nPos);
820 else
821 ++nPos;
824 else
826 //!!!!!!!!!!!!!!!!!! mit diesem Remove gibt es Abstuerze (Calc1 Import)
827 //! pDocument->GetPool()->Remove(*pNewPattern);
828 nStart = pData[nPos].nRow + 1;
829 ++nPos;
832 while (nStart <= nEndRow);
834 if (pDocument->IsStreamValid(nTab))
835 pDocument->SetStreamValid(nTab, FALSE);
838 #ifdef DBG_UTIL
839 TestData();
840 #endif
844 void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
846 const SfxPoolItem* pNewItem;
847 const SfxPoolItem* pOldItem;
848 for (USHORT nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
850 // pMergeSet hat keinen Parent
851 SfxItemState eOldState = rMergeSet.GetItemState( nId, FALSE, &pOldItem );
853 if ( eOldState == SFX_ITEM_DEFAULT ) // Default
855 SfxItemState eNewState = rSource.GetItemState( nId, TRUE, &pNewItem );
856 if ( eNewState == SFX_ITEM_SET )
858 if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
859 rMergeSet.InvalidateItem( nId );
862 else if ( eOldState == SFX_ITEM_SET ) // Item gesetzt
864 SfxItemState eNewState = rSource.GetItemState( nId, TRUE, &pNewItem );
865 if ( eNewState == SFX_ITEM_SET )
867 if ( pNewItem != pOldItem ) // beide gepuhlt
868 rMergeSet.InvalidateItem( nId );
870 else // Default
872 if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
873 rMergeSet.InvalidateItem( nId );
876 // Dontcare bleibt Dontcare
881 void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
882 ScMergePatternState& rState, BOOL bDeep ) const
884 if (ValidRow(nStartRow) && ValidRow(nEndRow))
886 SCSIZE nPos;
887 SCROW nStart=0;
888 if (!Search( nStartRow, nPos ))
890 DBG_ERROR("Search-Fehler");
891 return;
896 // gleiche Patterns muessen nicht mehrfach angesehen werden
898 const ScPatternAttr* pPattern = pData[nPos].pPattern;
899 if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
901 const SfxItemSet& rThisSet = pPattern->GetItemSet();
902 if (rState.pItemSet)
904 // (*ppSet)->MergeValues( rThisSet, FALSE );
905 // geht nicht, weil die Vorlagen nicht beruecksichtigt werden
907 if (bDeep)
908 lcl_MergeDeep( *rState.pItemSet, rThisSet );
909 else
910 rState.pItemSet->MergeValues( rThisSet, FALSE );
912 else
914 // erstes Pattern - in Set ohne Parent kopieren
915 rState.pItemSet = new SfxItemSet( *rThisSet.GetPool(), rThisSet.GetRanges() );
916 rState.pItemSet->Set( rThisSet, bDeep );
919 rState.pOld2 = rState.pOld1;
920 rState.pOld1 = pPattern;
923 nStart = pData[nPos].nRow + 1;
924 ++nPos;
926 while (nStart <= nEndRow);
932 // Umrandung zusammenbauen
934 BOOL lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
935 BYTE& rModified, const SvxBorderLine*& rpNew )
937 if (rModified == SC_LINE_DONTCARE)
938 return FALSE; // weiter geht's nicht
940 if (rModified == SC_LINE_EMPTY)
942 rModified = SC_LINE_SET;
943 rpNew = pNewLine;
944 return TRUE; // zum ersten mal gesetzt
947 if (pOldLine == pNewLine)
949 rpNew = pOldLine;
950 return FALSE;
953 if (pOldLine && pNewLine)
954 if (*pOldLine == *pNewLine)
956 rpNew = pOldLine;
957 return FALSE;
960 rModified = SC_LINE_DONTCARE;
961 rpNew = NULL;
962 return TRUE; // andere Linie -> dontcare
966 void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
967 ScLineFlags& rFlags, const ScPatternAttr* pPattern,
968 BOOL bLeft, SCCOL nDistRight, BOOL bTop, SCROW nDistBottom )
970 // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst:
971 const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
972 if ( rMerge.GetColMerge() == nDistRight + 1 )
973 nDistRight = 0;
974 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
975 nDistBottom = 0;
977 const SvxBoxItem* pCellFrame = (SvxBoxItem*) &pPattern->GetItemSet().Get( ATTR_BORDER );
978 const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft();
979 const SvxBorderLine* pRightAttr = pCellFrame->GetRight();
980 const SvxBorderLine* pTopAttr = pCellFrame->GetTop();
981 const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom();
982 const SvxBorderLine* pNew;
984 if (bTop)
986 if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
987 pLineOuter->SetLine( pNew, BOX_LINE_TOP );
989 else
991 if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew ))
992 pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
995 if (nDistBottom == 0)
997 if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew ))
998 pLineOuter->SetLine( pNew, BOX_LINE_BOTTOM );
1000 else
1002 if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
1003 pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
1006 if (bLeft)
1008 if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
1009 pLineOuter->SetLine( pNew, BOX_LINE_LEFT );
1011 else
1013 if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew ))
1014 pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
1017 if (nDistRight == 0)
1019 if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew ))
1020 pLineOuter->SetLine( pNew, BOX_LINE_RIGHT );
1022 else
1024 if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew ))
1025 pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
1030 void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
1031 ScLineFlags& rFlags,
1032 SCROW nStartRow, SCROW nEndRow, BOOL bLeft, SCCOL nDistRight ) const
1034 const ScPatternAttr* pPattern;
1036 if (nStartRow == nEndRow)
1038 pPattern = GetPattern( nStartRow );
1039 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, TRUE, 0 );
1041 else
1043 pPattern = GetPattern( nStartRow );
1044 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, TRUE,
1045 nEndRow-nStartRow );
1047 SCSIZE nStartIndex;
1048 SCSIZE nEndIndex;
1049 Search( nStartRow+1, nStartIndex );
1050 Search( nEndRow-1, nEndIndex );
1051 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1053 pPattern = (ScPatternAttr*) pData[i].pPattern;
1054 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, FALSE,
1055 nEndRow - Min( pData[i].nRow, (SCROW)(nEndRow-1) ) );
1056 // nDistBottom hier immer > 0
1059 pPattern = GetPattern( nEndRow );
1060 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, FALSE, 0 );
1065 // Rahmen anwenden
1068 // ApplyFrame - auf einen Eintrag im Array
1071 BOOL ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
1072 const SvxBoxInfoItem* pBoxInfoItem,
1073 SCROW nStartRow, SCROW nEndRow,
1074 BOOL bLeft, SCCOL nDistRight, BOOL bTop, SCROW nDistBottom )
1076 DBG_ASSERT( pBoxItem && pBoxInfoItem, "Linienattribute fehlen!" );
1078 const ScPatternAttr* pPattern = GetPattern( nStartRow );
1079 const SvxBoxItem* pOldFrame = (const SvxBoxItem*)
1080 &pPattern->GetItemSet().Get( ATTR_BORDER );
1082 // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst:
1083 const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
1084 if ( rMerge.GetColMerge() == nDistRight + 1 )
1085 nDistRight = 0;
1086 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1087 nDistBottom = 0;
1089 SvxBoxItem aNewFrame( *pOldFrame );
1091 if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
1092 aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1093 BOX_LINE_LEFT );
1094 if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
1095 aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1096 BOX_LINE_RIGHT );
1097 if ( bTop ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) )
1098 aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
1099 BOX_LINE_TOP );
1100 if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) )
1101 aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(),
1102 BOX_LINE_BOTTOM );
1104 if (aNewFrame == *pOldFrame)
1106 // nothing to do
1107 return FALSE;
1109 else
1111 SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
1112 ApplyCacheArea( nStartRow, nEndRow, &aCache );
1114 /* ScPatternAttr* pNewPattern = (ScPatternAttr*) pPattern->Clone();
1115 pNewPattern->GetItemSet().Put( aNewFrame );
1116 SetPatternArea( nStartRow, nEndRow, pNewPattern, TRUE );
1118 return TRUE;
1123 void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
1124 SCROW nStartRow, SCROW nEndRow, BOOL bLeft, SCCOL nDistRight )
1126 if (nStartRow == nEndRow)
1127 ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, TRUE, 0 );
1128 else
1130 ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
1131 TRUE, nEndRow-nStartRow );
1133 if ( nEndRow > nStartRow+1 ) // innerer Teil vorhanden?
1135 SCSIZE nStartIndex;
1136 SCSIZE nEndIndex;
1137 Search( nStartRow+1, nStartIndex );
1138 Search( nEndRow-1, nEndIndex );
1139 SCROW nTmpStart = nStartRow+1;
1140 SCROW nTmpEnd;
1141 for (SCSIZE i=nStartIndex; i<=nEndIndex;)
1143 nTmpEnd = Min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) );
1144 BOOL bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd,
1145 bLeft, nDistRight, FALSE, nEndRow-nTmpEnd );
1146 nTmpStart = nTmpEnd+1;
1147 if (bChanged)
1149 Search(nTmpStart, i);
1150 Search(nEndRow-1, nEndIndex);
1152 else
1153 i++;
1157 ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, FALSE, 0 );
1162 long lcl_LineSize( const SvxBorderLine& rLine )
1164 // nur eine Linie -> halbe Breite, min. 20
1165 // doppelte Linie -> halber Abstand + eine Linie (je min. 20)
1167 long nTotal = 0;
1168 USHORT nWidth = Max( rLine.GetOutWidth(), rLine.GetInWidth() );
1169 USHORT nDist = rLine.GetDistance();
1170 if (nDist)
1172 DBG_ASSERT( rLine.GetOutWidth() && rLine.GetInWidth(),
1173 "Linie hat Abstand, aber nur eine Breite ???" );
1175 // nTotal += ( nDist > 40 ) ? ( nDist / 2 ) : 20;
1176 nTotal += ( nDist > 20 ) ? nDist : 20;
1177 nTotal += ( nWidth > 20 ) ? nWidth : 20;
1179 else if (nWidth)
1180 // nTotal += ( nWidth > 40 ) ? ( nWidth / 2 ) : 20;
1181 nTotal += ( nWidth > 20 ) ? nWidth : 20;
1183 //! auch halbieren ???
1185 return nTotal;
1189 BOOL ScAttrArray::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
1190 BOOL bLeft, BOOL bRight ) const
1192 SCSIZE nStartIndex;
1193 SCSIZE nEndIndex;
1194 Search( nRow1, nStartIndex );
1195 Search( nRow2, nEndIndex );
1196 BOOL bFound = FALSE;
1198 const SvxBoxItem* pItem = 0;
1199 const SvxBorderLine* pLine = 0;
1200 long nCmp;
1202 // oben
1204 pItem = (const SvxBoxItem*) &pData[nStartIndex].pPattern->GetItem(ATTR_BORDER);
1205 pLine = pItem->GetTop();
1206 if (pLine)
1208 nCmp = lcl_LineSize(*pLine);
1209 if ( nCmp > rSizes.Top() )
1210 rSizes.Top() = nCmp;
1211 bFound = TRUE;
1214 // unten
1216 if ( nEndIndex != nStartIndex )
1217 pItem = (const SvxBoxItem*) &pData[nEndIndex].pPattern->GetItem(ATTR_BORDER);
1218 pLine = pItem->GetBottom();
1219 if (pLine)
1221 nCmp = lcl_LineSize(*pLine);
1222 if ( nCmp > rSizes.Bottom() )
1223 rSizes.Bottom() = nCmp;
1224 bFound = TRUE;
1227 if ( bLeft || bRight )
1228 for ( SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1230 pItem = (const SvxBoxItem*) &pData[i].pPattern->GetItem(ATTR_BORDER);
1232 // links
1234 if (bLeft)
1236 pLine = pItem->GetLeft();
1237 if (pLine)
1239 nCmp = lcl_LineSize(*pLine);
1240 if ( nCmp > rSizes.Left() )
1241 rSizes.Left() = nCmp;
1242 bFound = TRUE;
1246 // rechts
1248 if (bRight)
1250 pLine = pItem->GetRight();
1251 if (pLine)
1253 nCmp = lcl_LineSize(*pLine);
1254 if ( nCmp > rSizes.Right() )
1255 rSizes.Right() = nCmp;
1256 bFound = TRUE;
1261 return bFound;
1264 // Testen, ob Bereich bestimmtes Attribut enthaelt
1266 BOOL ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, USHORT nMask ) const
1268 SCSIZE nStartIndex;
1269 SCSIZE nEndIndex;
1270 Search( nRow1, nStartIndex );
1271 Search( nRow2, nEndIndex );
1272 BOOL bFound = FALSE;
1274 for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
1276 const ScPatternAttr* pPattern = pData[i].pPattern;
1277 if ( nMask & HASATTR_MERGED )
1279 const ScMergeAttr* pMerge =
1280 (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1281 if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
1282 bFound = TRUE;
1284 if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) )
1286 const ScMergeFlagAttr* pMergeFlag =
1287 (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG );
1288 if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() )
1289 bFound = TRUE;
1290 if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() )
1291 bFound = TRUE;
1292 if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() )
1293 bFound = TRUE;
1295 if ( nMask & HASATTR_LINES )
1297 const SvxBoxItem* pBox =
1298 (const SvxBoxItem*) &pPattern->GetItem( ATTR_BORDER );
1299 if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
1300 bFound = TRUE;
1302 if ( nMask & HASATTR_SHADOW )
1304 const SvxShadowItem* pShadow =
1305 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1306 if ( pShadow->GetLocation() != SVX_SHADOW_NONE )
1307 bFound = TRUE;
1309 if ( nMask & HASATTR_CONDITIONAL )
1311 const SfxUInt32Item* pConditional =
1312 (const SfxUInt32Item*) &pPattern->GetItem( ATTR_CONDITIONAL );
1313 if ( pConditional->GetValue() != 0 )
1314 bFound = TRUE;
1316 if ( nMask & HASATTR_PROTECTED )
1318 const ScProtectionAttr* pProtect =
1319 (const ScProtectionAttr*) &pPattern->GetItem( ATTR_PROTECTION );
1320 if ( pProtect->GetProtection() || pProtect->GetHideCell() )
1321 bFound = TRUE;
1323 if ( nMask & HASATTR_ROTATE )
1325 const SfxInt32Item* pRotate =
1326 (const SfxInt32Item*) &pPattern->GetItem( ATTR_ROTATE_VALUE );
1327 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1328 // (see ScPatternAttr::GetCellOrientation)
1329 INT32 nAngle = pRotate->GetValue();
1330 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
1331 bFound = TRUE;
1333 if ( nMask & HASATTR_NEEDHEIGHT )
1335 if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
1336 bFound = TRUE;
1337 else if (((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue())
1338 bFound = TRUE;
1339 else if ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
1340 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK)
1341 bFound = TRUE;
1342 else if (((const SfxUInt32Item&)pPattern->GetItem( ATTR_CONDITIONAL )).GetValue())
1343 bFound = TRUE;
1344 else if (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue())
1345 bFound = TRUE;
1347 if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) )
1349 const SvxShadowItem* pShadow =
1350 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1351 SvxShadowLocation eLoc = pShadow->GetLocation();
1352 if ( nMask & HASATTR_SHADOW_RIGHT )
1353 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1354 bFound = TRUE;
1355 if ( nMask & HASATTR_SHADOW_DOWN )
1356 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1357 bFound = TRUE;
1359 if ( nMask & HASATTR_RTL )
1361 const SvxFrameDirectionItem& rDirection =
1362 (const SvxFrameDirectionItem&) pPattern->GetItem( ATTR_WRITINGDIR );
1363 if ( rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP )
1364 bFound = TRUE;
1366 if ( nMask & HASATTR_RIGHTORCENTER )
1368 // called only if the sheet is LTR, so physical=logical alignment can be assumed
1369 SvxCellHorJustify eHorJust = (SvxCellHorJustify)
1370 ((const SvxHorJustifyItem&) pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
1371 if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER )
1372 bFound = TRUE;
1376 return bFound;
1379 // Bereich um evtl. enthaltene Zusammenfassungen erweitern
1380 // und evtl. MergeFlag anpassen (bRefresh)
1382 BOOL ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
1383 SCCOL& rPaintCol, SCROW& rPaintRow,
1384 BOOL bRefresh, BOOL bAttrs )
1386 const ScPatternAttr* pPattern;
1387 const ScMergeAttr* pItem;
1388 SCSIZE nStartIndex;
1389 SCSIZE nEndIndex;
1390 Search( nStartRow, nStartIndex );
1391 Search( nEndRow, nEndIndex );
1392 BOOL bFound = FALSE;
1394 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1396 pPattern = pData[i].pPattern;
1397 pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1398 SCsCOL nCountX = pItem->GetColMerge();
1399 SCsROW nCountY = pItem->GetRowMerge();
1400 if (nCountX>1 || nCountY>1)
1402 SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0;
1403 SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1404 SCROW nMergeEndRow = nThisRow + nCountY - 1;
1405 if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL)
1406 rPaintCol = nMergeEndCol;
1407 if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW)
1408 rPaintRow = nMergeEndRow;
1409 bFound = TRUE;
1411 if (bAttrs)
1413 const SvxShadowItem* pShadow =
1414 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1415 SvxShadowLocation eLoc = pShadow->GetLocation();
1416 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1417 if ( nMergeEndCol+1 > rPaintCol && nMergeEndCol < MAXCOL )
1418 rPaintCol = nMergeEndCol+1;
1419 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1420 if ( nMergeEndRow+1 > rPaintRow && nMergeEndRow < MAXROW )
1421 rPaintRow = nMergeEndRow+1;
1424 if (bRefresh)
1426 if ( nMergeEndCol > nThisCol )
1427 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow,
1428 nTab, SC_MF_HOR );
1429 if ( nMergeEndRow > nThisRow )
1430 pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
1431 nTab, SC_MF_VER );
1432 if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
1433 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
1434 nTab, SC_MF_HOR | SC_MF_VER );
1436 Search( nThisRow, i ); // Daten wurden veraendert
1437 Search( nStartRow, nStartIndex );
1438 Search( nEndRow, nEndIndex );
1443 return bFound;
1447 BOOL ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
1449 BOOL bFound = FALSE;
1450 const ScPatternAttr* pPattern;
1451 const ScMergeAttr* pItem;
1452 SCSIZE nIndex;
1454 Search( nStartRow, nIndex );
1455 SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1456 if (nThisStart < nStartRow)
1457 nThisStart = nStartRow;
1459 while ( nThisStart <= nEndRow )
1461 SCROW nThisEnd = pData[nIndex].nRow;
1462 if (nThisEnd > nEndRow)
1463 nThisEnd = nEndRow;
1465 pPattern = pData[nIndex].pPattern;
1466 pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1467 SCsCOL nCountX = pItem->GetColMerge();
1468 SCsROW nCountY = pItem->GetRowMerge();
1469 if (nCountX>1 || nCountY>1)
1471 const ScMergeAttr* pAttr = (const ScMergeAttr*)
1472 &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
1473 const ScMergeFlagAttr* pFlagAttr = (const ScMergeFlagAttr*)
1474 &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG );
1476 DBG_ASSERT( nCountY==1 || nThisStart==nThisEnd, "was'n hier los?" );
1478 SCCOL nThisCol = nCol;
1479 SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1480 SCROW nMergeEndRow = nThisEnd + nCountY - 1;
1482 //! ApplyAttr fuer Bereiche !!!
1484 for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
1485 pDocument->ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
1487 ScPatternAttr* pNewPattern = new ScPatternAttr( pDocument->GetPool() );
1488 SfxItemSet* pSet = &pNewPattern->GetItemSet();
1489 pSet->Put( *pFlagAttr );
1490 pDocument->ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
1491 nTab, *pNewPattern );
1492 delete pNewPattern;
1494 Search( nThisEnd, nIndex ); // Daten wurden veraendert !!!
1497 ++nIndex;
1498 if ( nIndex < nCount )
1499 nThisStart = pData[nIndex-1].nRow+1;
1500 else
1501 nThisStart = MAXROW+1; // Ende
1504 return bFound;
1507 // Bereich loeschen, aber Merge-Flags stehenlassen
1509 void ScAttrArray::DeleteAreaSafe(SCROW nStartRow, SCROW nEndRow)
1511 SetPatternAreaSafe( nStartRow, nEndRow, pDocument->GetDefPattern(), TRUE );
1515 void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
1516 const ScPatternAttr* pWantedPattern, BOOL bDefault )
1518 const ScPatternAttr* pOldPattern;
1519 const ScMergeFlagAttr* pItem;
1521 SCSIZE nIndex;
1522 SCROW nRow;
1523 SCROW nThisRow;
1524 BOOL bFirstUse = TRUE;
1526 Search( nStartRow, nIndex );
1527 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1528 while ( nThisRow <= nEndRow )
1530 pOldPattern = pData[nIndex].pPattern;
1531 if (pOldPattern != pWantedPattern) //! else-Zweig ?
1533 if (nThisRow < nStartRow) nThisRow = nStartRow;
1534 nRow = pData[nIndex].nRow;
1535 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1536 pItem = (const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG );
1538 if (pItem->IsOverlapped() || pItem->HasAutoFilter())
1540 // #108045# default-constructing a ScPatternAttr for DeleteArea doesn't work
1541 // because it would have no cell style information.
1542 // Instead, the document's GetDefPattern is copied. Since it is passed as
1543 // pWantedPattern, no special treatment of default is needed here anymore.
1544 ScPatternAttr* pNewPattern = new ScPatternAttr( *pWantedPattern );
1545 SfxItemSet* pSet = &pNewPattern->GetItemSet();
1546 pSet->Put( *pItem );
1547 SetPatternArea( nThisRow, nAttrRow, pNewPattern, TRUE );
1548 delete pNewPattern;
1550 else
1552 if ( !bDefault )
1554 if (bFirstUse)
1555 bFirstUse = FALSE;
1556 else
1557 pDocument->GetPool()->Put( *pWantedPattern ); // im Pool ist es schon!
1559 SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
1562 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1565 ++nIndex;
1566 nThisRow = pData[nIndex-1].nRow+1;
1571 BOOL ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, INT16 nFlags )
1573 const ScPatternAttr* pOldPattern;
1575 INT16 nOldValue;
1576 SCSIZE nIndex;
1577 SCROW nRow;
1578 SCROW nThisRow;
1579 BOOL bChanged = FALSE;
1581 Search( nStartRow, nIndex );
1582 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1583 if (nThisRow < nStartRow) nThisRow = nStartRow;
1585 while ( nThisRow <= nEndRow )
1587 pOldPattern = pData[nIndex].pPattern;
1588 nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1589 if ( (nOldValue | nFlags) != nOldValue )
1591 nRow = pData[nIndex].nRow;
1592 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1593 ScPatternAttr aNewPattern(*pOldPattern);
1594 aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
1595 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
1596 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1597 bChanged = TRUE;
1600 ++nIndex;
1601 nThisRow = pData[nIndex-1].nRow+1;
1604 return bChanged;
1608 BOOL ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, INT16 nFlags )
1610 const ScPatternAttr* pOldPattern;
1612 INT16 nOldValue;
1613 SCSIZE nIndex;
1614 SCROW nRow;
1615 SCROW nThisRow;
1616 BOOL bChanged = FALSE;
1618 Search( nStartRow, nIndex );
1619 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1620 if (nThisRow < nStartRow) nThisRow = nStartRow;
1622 while ( nThisRow <= nEndRow )
1624 pOldPattern = pData[nIndex].pPattern;
1625 nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1626 if ( (nOldValue & ~nFlags) != nOldValue )
1628 nRow = pData[nIndex].nRow;
1629 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1630 ScPatternAttr aNewPattern(*pOldPattern);
1631 aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
1632 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
1633 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1634 bChanged = TRUE;
1637 ++nIndex;
1638 nThisRow = pData[nIndex-1].nRow+1;
1641 return bChanged;
1645 void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const USHORT* pWhich )
1647 const ScPatternAttr* pOldPattern;
1649 SCSIZE nIndex;
1650 SCROW nRow;
1651 SCROW nThisRow;
1653 Search( nStartRow, nIndex );
1654 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1655 if (nThisRow < nStartRow) nThisRow = nStartRow;
1657 while ( nThisRow <= nEndRow )
1659 pOldPattern = pData[nIndex].pPattern;
1660 if ( pOldPattern->HasItemsSet( pWhich ) )
1662 ScPatternAttr aNewPattern(*pOldPattern);
1663 aNewPattern.ClearItems( pWhich );
1665 nRow = pData[nIndex].nRow;
1666 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1667 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
1668 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1671 ++nIndex;
1672 nThisRow = pData[nIndex-1].nRow+1;
1677 void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, BOOL bIncrement )
1679 SCSIZE nIndex;
1680 Search( nStartRow, nIndex );
1681 SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1682 if (nThisStart < nStartRow) nThisStart = nStartRow;
1684 while ( nThisStart <= nEndRow )
1686 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
1687 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
1688 const SfxPoolItem* pItem;
1690 BOOL bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, FALSE, &pItem ) != SFX_ITEM_SET
1691 || ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT );
1692 USHORT nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue();
1693 USHORT nNewValue = nOldValue;
1694 if ( bIncrement )
1696 if ( nNewValue < SC_MAX_INDENT )
1698 nNewValue += SC_INDENT_STEP;
1699 if ( nNewValue > SC_MAX_INDENT ) nNewValue = SC_MAX_INDENT;
1702 else
1704 if ( nNewValue > 0 )
1706 if ( nNewValue > SC_INDENT_STEP )
1707 nNewValue -= SC_INDENT_STEP;
1708 else
1709 nNewValue = 0;
1713 if ( bNeedJust || nNewValue != nOldValue )
1715 SCROW nThisEnd = pData[nIndex].nRow;
1716 SCROW nAttrRow = Min( nThisEnd, nEndRow );
1717 ScPatternAttr aNewPattern(*pOldPattern);
1718 aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) );
1719 if ( bNeedJust )
1720 aNewPattern.GetItemSet().Put(
1721 SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
1722 SetPatternArea( nThisStart, nAttrRow, &aNewPattern, TRUE );
1724 nThisStart = nThisEnd + 1;
1725 Search( nThisStart, nIndex ); // Daten wurden veraendert !!!
1727 else
1729 nThisStart = pData[nIndex].nRow + 1; // weiterzaehlen...
1730 ++nIndex;
1736 SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, BOOL bUp ) const
1738 long nRet = nRow;
1739 if (VALIDROW(nRow))
1741 SCSIZE nIndex;
1742 Search(nRow, nIndex);
1743 while (((const ScProtectionAttr&)pData[nIndex].pPattern->
1744 GetItem(ATTR_PROTECTION)).GetProtection())
1746 if (bUp)
1748 if (nIndex==0)
1749 return -1; // nichts gefunden
1750 --nIndex;
1751 nRet = pData[nIndex].nRow;
1753 else
1755 nRet = pData[nIndex].nRow+1;
1756 ++nIndex;
1757 if (nIndex>=nCount)
1758 return MAXROW+1; // nichts gefunden
1762 return nRet;
1765 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
1767 SCROW nStart = 0;
1768 SCSIZE nPos = 0;
1769 while (nPos < nCount)
1771 SCROW nEnd = pData[nPos].nRow;
1772 if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
1774 // for (SCROW nRow = nStart; nRow <= nEnd; nRow++)
1775 // pUsed[nRow] = TRUE;
1777 rUsedRows.setTrue(nStart, nEnd);
1779 if (bReset)
1781 ScPatternAttr* pNewPattern = new ScPatternAttr(*pData[nPos].pPattern);
1782 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
1783 pNewPattern->SetStyleSheet( (ScStyleSheet*)
1784 pDocument->GetStyleSheetPool()->
1785 Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD),
1786 SFX_STYLE_FAMILY_PARA,
1787 SFXSTYLEBIT_AUTO | SCSTYLEBIT_STANDARD ) );
1788 pData[nPos].pPattern = (const ScPatternAttr*)
1789 &pDocument->GetPool()->Put(*pNewPattern);
1790 delete pNewPattern;
1792 if (Concat(nPos))
1794 Search(nStart, nPos);
1795 --nPos; // wegen ++ am Ende
1799 nStart = nEnd + 1;
1800 ++nPos;
1805 BOOL ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
1806 BOOL bGatherAllStyles ) const
1808 BOOL bIsUsed = FALSE;
1809 SCSIZE nPos = 0;
1811 while ( nPos < nCount )
1813 const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet();
1814 if ( pStyle )
1816 pStyle->SetUsage( ScStyleSheet::USED );
1817 if ( pStyle == &rStyle )
1819 if ( !bGatherAllStyles )
1820 return TRUE;
1821 bIsUsed = TRUE;
1824 nPos++;
1827 return bIsUsed;
1831 BOOL ScAttrArray::IsEmpty() const
1833 if (nCount == 1)
1835 if ( pData[0].pPattern != pDocument->GetDefPattern() )
1836 return FALSE;
1837 else
1838 return TRUE;
1840 else
1841 return FALSE;
1845 //UNUSED2008-05 SCROW ScAttrArray::GetFirstEntryPos() const
1846 //UNUSED2008-05 {
1847 //UNUSED2008-05 DBG_ASSERT( nCount, "nCount = 0" );
1848 //UNUSED2008-05
1849 //UNUSED2008-05 if ( pData[0].pPattern != pDocument->GetDefPattern() )
1850 //UNUSED2008-05 return 0;
1851 //UNUSED2008-05 else
1852 //UNUSED2008-05 {
1853 //UNUSED2008-05 if (nCount==1)
1854 //UNUSED2008-05 return 0; // leer
1855 //UNUSED2008-05 else
1856 //UNUSED2008-05 return pData[0].nRow + 1;
1857 //UNUSED2008-05 }
1858 //UNUSED2008-05 }
1859 //UNUSED2008-05
1860 //UNUSED2008-05
1861 //UNUSED2008-05 SCROW ScAttrArray::GetLastEntryPos( BOOL bIncludeBottom ) const
1862 //UNUSED2008-05 {
1863 //UNUSED2008-05 DBG_ASSERT( nCount, "nCount == 0" );
1864 //UNUSED2008-05
1865 //UNUSED2008-05 if (bIncludeBottom)
1866 //UNUSED2008-05 bIncludeBottom = ( pData[nCount-1].pPattern != pDocument->GetDefPattern() );
1867 //UNUSED2008-05
1868 //UNUSED2008-05 if (bIncludeBottom)
1869 //UNUSED2008-05 return MAXROW;
1870 //UNUSED2008-05 else
1871 //UNUSED2008-05 {
1872 //UNUSED2008-05 if (nCount<=1)
1873 //UNUSED2008-05 return 0; // leer
1874 //UNUSED2008-05 else
1875 //UNUSED2008-05 return pData[nCount-2].nRow;
1876 //UNUSED2008-05 }
1877 //UNUSED2008-05 }
1880 BOOL ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1882 DBG_ASSERT( nCount, "nCount == 0" );
1884 BOOL bFound = FALSE;
1885 SCSIZE nStart = 0;
1887 // Skip first entry if more than 1 row.
1888 // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1890 SCSIZE nVisStart = 1;
1891 while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) )
1892 ++nVisStart;
1893 if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 ) // more than 1 row?
1894 nStart = nVisStart;
1896 while ( nStart < nCount && !bFound )
1898 if ( pData[nStart].pPattern->IsVisible() )
1900 rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0;
1901 bFound = TRUE;
1903 else
1904 ++nStart;
1907 return bFound;
1910 // size (rows) of a range of attributes after cell content where the search is stopped
1911 // (more than a default page size, 2*42 because it's as good as any number)
1913 const SCROW SC_VISATTR_STOP = 84;
1915 BOOL ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
1917 // #i30830# changed behavior:
1918 // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1919 // below the last content cell
1921 if ( nLastData == MAXROW )
1923 rLastRow = MAXROW; // can't look for attributes below MAXROW
1924 return TRUE;
1927 BOOL bFound = FALSE;
1929 // loop backwards from the end instead of using Search, assuming that
1930 // there usually aren't many attributes below the last cell
1932 SCSIZE nPos = nCount;
1933 while ( nPos > 0 && pData[nPos-1].nRow > nLastData )
1935 SCSIZE nEndPos = nPos - 1;
1936 SCSIZE nStartPos = nEndPos; // find range of visually equal formats
1937 while ( nStartPos > 0 &&
1938 pData[nStartPos-1].nRow > nLastData &&
1939 pData[nStartPos-1].pPattern->IsVisibleEqual(*pData[nStartPos].pPattern) )
1940 --nStartPos;
1942 SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos-1].nRow + 1 ) : 0;
1943 if ( nAttrStartRow <= nLastData )
1944 nAttrStartRow = nLastData + 1;
1945 SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
1946 if ( nAttrSize >= SC_VISATTR_STOP )
1948 bFound = FALSE; // ignore this range and below
1950 else if ( !bFound && pData[nEndPos].pPattern->IsVisible() )
1952 rLastRow = pData[nEndPos].nRow;
1953 bFound = TRUE;
1956 nPos = nStartPos; // look further from the top of the range
1959 return bFound;
1963 BOOL ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1965 SCSIZE nIndex;
1966 Search( nStartRow, nIndex );
1967 SCROW nThisStart = nStartRow;
1968 BOOL bFound = FALSE;
1969 while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
1971 if ( pData[nIndex].pPattern->IsVisible() )
1972 bFound = TRUE;
1974 nThisStart = pData[nIndex].nRow + 1;
1975 ++nIndex;
1978 return bFound;
1982 BOOL ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
1983 SCROW nStartRow, SCROW nEndRow ) const
1985 BOOL bEqual = TRUE;
1986 SCSIZE nThisPos = 0;
1987 SCSIZE nOtherPos = 0;
1988 if ( nStartRow > 0 )
1990 Search( nStartRow, nThisPos );
1991 rOther.Search( nStartRow, nOtherPos );
1994 while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1996 SCROW nThisRow = pData[nThisPos].nRow;
1997 SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
1998 const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
1999 const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
2000 bEqual = ( pThisPattern == pOtherPattern ||
2001 pThisPattern->IsVisibleEqual(*pOtherPattern) );
2003 if ( nThisRow >= nOtherRow )
2005 if ( nOtherRow >= nEndRow ) break;
2006 ++nOtherPos;
2008 if ( nThisRow <= nOtherRow )
2010 if ( nThisRow >= nEndRow ) break;
2011 ++nThisPos;
2015 return bEqual;
2019 BOOL ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
2021 //! mit IsVisibleEqual zusammenfassen?
2023 BOOL bEqual = TRUE;
2024 SCSIZE nThisPos = 0;
2025 SCSIZE nOtherPos = 0;
2026 if ( nStartRow > 0 )
2028 Search( nStartRow, nThisPos );
2029 rOther.Search( nStartRow, nOtherPos );
2032 while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
2034 SCROW nThisRow = pData[nThisPos].nRow;
2035 SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
2036 const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
2037 const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
2038 bEqual = ( pThisPattern == pOtherPattern );
2040 if ( nThisRow >= nOtherRow )
2042 if ( nOtherRow >= nEndRow ) break;
2043 ++nOtherPos;
2045 if ( nThisRow <= nOtherRow )
2047 if ( nThisRow >= nEndRow ) break;
2048 ++nThisPos;
2052 return bEqual;
2056 BOOL ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
2058 // horizontal zusammengefasste duerfen nicht herausgeschoben werden
2059 // (ob die ganze Zusammenfassung betroffen ist, ist hier nicht zu erkennen)
2061 BOOL bTest = TRUE;
2062 if (!IsEmpty())
2064 SCSIZE nIndex = 0;
2065 if ( nStartRow > 0 )
2066 Search( nStartRow, nIndex );
2068 for ( ; nIndex < nCount; nIndex++ )
2070 if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern->
2071 GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
2073 bTest = FALSE; // darf nicht herausgeschoben werden
2074 break;
2076 if ( pData[nIndex].nRow >= nEndRow ) // Ende des Bereichs
2077 break;
2080 return bTest;
2084 BOOL ScAttrArray::TestInsertRow( SCSIZE nSize ) const
2086 // wenn die erste herausgeschobene Zeile vertikal ueberlappt ist,
2087 // wuerde eine kaputte Zusammenfassung uebrigbleiben
2089 if (pData)
2091 // MAXROW + 1 - nSize = erste herausgeschobene Zeile
2093 SCSIZE nFirstLost = nCount-1;
2094 while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
2095 --nFirstLost;
2097 if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern->
2098 GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
2099 return FALSE;
2102 return TRUE;
2106 void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2108 if (!pData)
2109 return;
2111 SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // Vorgaenger erweitern
2112 SCSIZE nIndex;
2113 Search( nSearch, nIndex );
2115 // ein gesetztes ScMergeAttr darf nicht ausgedehnt werden
2116 // (darum hinterher wieder loeschen)
2118 BOOL bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
2120 SCSIZE nRemove = 0;
2121 SCSIZE i;
2122 for (i = nIndex; i < nCount-1; i++)
2124 SCROW nNew = pData[i].nRow + nSize;
2125 if ( nNew >= MAXROW ) // Ende erreicht ?
2127 nNew = MAXROW;
2128 if (!nRemove)
2129 nRemove = i+1; // folgende loeschen
2131 pData[i].nRow = nNew;
2134 // muessen Eintraege am Ende geloescht werden?
2136 if (nRemove && nRemove < nCount)
2137 DeleteRange( nRemove, nCount-1 );
2139 if (bDoMerge) // ausgedehntes ScMergeAttr wieder reparieren
2141 //! ApplyAttr fuer Bereiche !!!
2143 const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
2144 for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
2145 pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
2147 // im eingefuegten Bereich ist nichts zusammengefasst
2150 // Don't duplicate the merge flags in the inserted row.
2151 RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_ALL );
2155 void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
2157 if (pData)
2159 BOOL bFirst=TRUE;
2160 SCSIZE nStartIndex = 0;
2161 SCSIZE nEndIndex = 0;
2162 SCSIZE i;
2164 for ( i = 0; i < nCount-1; i++)
2165 if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
2167 if (bFirst)
2169 nStartIndex = i;
2170 bFirst = FALSE;
2172 nEndIndex = i;
2174 if (!bFirst)
2176 SCROW nStart;
2177 if (nStartIndex==0)
2178 nStart = 0;
2179 else
2180 nStart = pData[nStartIndex-1].nRow + 1;
2182 if (nStart < nStartRow)
2184 pData[nStartIndex].nRow = nStartRow - 1;
2185 ++nStartIndex;
2187 if (nEndIndex >= nStartIndex)
2189 DeleteRange( nStartIndex, nEndIndex );
2190 if (nStartIndex > 0)
2191 if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern )
2192 DeleteRange( nStartIndex-1, nStartIndex-1 );
2195 for (i = 0; i < nCount-1; i++)
2196 if (pData[i].nRow >= nStartRow)
2197 pData[i].nRow -= nSize;
2199 // unten nicht Default-Pattern nachschieben, um Druckbereiche erkennen zu koennen
2200 // stattdessen nur Merge-Flags loeschen
2202 RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
2207 void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
2209 ScDocumentPool* pDocPool = pDocument->GetPool();
2210 for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
2211 pDocPool->Remove(*pData[i].pPattern);
2213 memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) );
2214 nCount -= nEndIndex-nStartIndex+1;
2218 void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
2220 RemoveAreaMerge( nStartRow, nEndRow ); // von zusammengefassten auch die Flags loeschen
2222 if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) )
2223 SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
2224 else
2225 DeleteAreaSafe( nStartRow, nEndRow ); // Merge-Flags stehenlassen
2229 void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
2231 const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
2232 const ScPatternAttr* pOldPattern;
2234 SCSIZE nIndex;
2235 SCROW nRow;
2236 SCROW nThisRow;
2238 Search( nStartRow, nIndex );
2239 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
2240 if (nThisRow < nStartRow) nThisRow = nStartRow;
2242 while ( nThisRow <= nEndRow )
2244 pOldPattern = pData[nIndex].pPattern;
2246 if ( pOldPattern->GetItemSet().Count() ) // harte Attribute ?
2248 nRow = pData[nIndex].nRow;
2249 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
2251 ScPatternAttr aNewPattern(*pOldPattern);
2252 SfxItemSet& rSet = aNewPattern.GetItemSet();
2253 for (USHORT nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
2254 if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
2255 rSet.ClearItem(nId);
2257 if ( aNewPattern == *pDefPattern )
2258 SetPatternArea( nThisRow, nAttrRow, pDefPattern, FALSE );
2259 else
2260 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
2262 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
2265 ++nIndex;
2266 nThisRow = pData[nIndex-1].nRow+1;
2270 // Verschieben innerhalb eines Dokuments
2272 void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
2274 SCROW nStart = nStartRow;
2275 for (SCSIZE i = 0; i < nCount; i++)
2277 if ((pData[i].nRow >= nStartRow) && ((i==0) ? TRUE : pData[i-1].nRow < nEndRow))
2279 // Kopieren (bPutToPool=TRUE)
2280 rAttrArray.SetPatternArea( nStart, Min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
2281 pData[i].pPattern, TRUE );
2283 nStart = Max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) );
2285 DeleteArea(nStartRow, nEndRow);
2289 // Kopieren zwischen Dokumenten (Clipboard)
2291 void ScAttrArray::CopyArea( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray,
2292 INT16 nStripFlags )
2294 nStartRow -= nDy; // Source
2295 nEndRow -= nDy;
2297 SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
2298 SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
2300 ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2301 ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2302 BOOL bSamePool = (pSourceDocPool==pDestDocPool);
2304 for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2306 if (pData[i].nRow >= nStartRow)
2308 const ScPatternAttr* pOldPattern = pData[i].pPattern;
2309 const ScPatternAttr* pNewPattern;
2311 if (IsDefaultItem( pOldPattern ))
2313 // am Default muss nichts veraendert werden
2315 pNewPattern = (const ScPatternAttr*)
2316 &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2318 else if ( nStripFlags )
2320 ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern );
2321 INT16 nNewFlags = 0;
2322 if ( nStripFlags != SC_MF_ALL )
2323 nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)).
2324 GetValue() & ~nStripFlags;
2326 if ( nNewFlags )
2327 pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2328 else
2329 pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2331 if (bSamePool)
2332 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern);
2333 else
2334 pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
2335 delete pTmpPattern;
2337 else
2339 if (bSamePool)
2340 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2341 else
2342 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2345 rAttrArray.SetPatternArea(nDestStart,
2346 Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern);
2349 // when pasting from clipboard and skipping filtered rows, the adjusted end position
2350 // can be negative
2351 nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2355 // Flags stehenlassen
2356 //! mit CopyArea zusammenfassen !!!
2358 void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
2360 nStartRow -= nDy; // Source
2361 nEndRow -= nDy;
2363 SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
2364 SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
2366 if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) )
2368 CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
2369 return;
2372 ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2373 ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2374 BOOL bSamePool = (pSourceDocPool==pDestDocPool);
2376 for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2378 if (pData[i].nRow >= nStartRow)
2380 const ScPatternAttr* pOldPattern = pData[i].pPattern;
2381 const ScPatternAttr* pNewPattern;
2383 if (bSamePool)
2384 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2385 else
2386 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2388 rAttrArray.SetPatternAreaSafe(nDestStart,
2389 Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, FALSE);
2392 // when pasting from clipboard and skipping filtered rows, the adjusted end position
2393 // can be negative
2394 nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2399 SCsROW ScAttrArray::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
2400 BOOL bUp, ScMarkArray* pMarkArray )
2402 BOOL bFound = FALSE;
2404 if (pMarkArray)
2406 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2407 if (!VALIDROW(nRow))
2408 return nRow;
2411 SCSIZE nIndex;
2412 Search(nRow, nIndex);
2413 const ScPatternAttr* pPattern = pData[nIndex].pPattern;
2415 while (nIndex < nCount && !bFound)
2417 if (pPattern->GetStyleSheet() == pSearchStyle)
2419 if (pMarkArray)
2421 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2422 SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
2423 if (nRow >= nStart && nRow <= pData[nIndex].nRow)
2424 bFound = TRUE;
2426 else
2427 bFound = TRUE;
2430 if (!bFound)
2432 if (bUp)
2434 if (nIndex==0)
2436 nIndex = nCount;
2437 nRow = -1;
2439 else
2441 --nIndex;
2442 nRow = pData[nIndex].nRow;
2443 pPattern = pData[nIndex].pPattern;
2446 else
2448 nRow = pData[nIndex].nRow+1;
2449 ++nIndex;
2450 if (nIndex<nCount)
2451 pPattern = pData[nIndex].pPattern;
2456 DBG_ASSERT( bFound || !ValidRow(nRow), "interner Fehler in ScAttrArray::SearchStyle" );
2458 return nRow;
2462 BOOL ScAttrArray::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow,
2463 const ScStyleSheet* pSearchStyle, BOOL bUp, ScMarkArray* pMarkArray )
2465 SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
2466 if (VALIDROW(nStartRow))
2468 SCSIZE nIndex;
2469 Search(nStartRow,nIndex);
2471 rRow = nStartRow;
2472 if (bUp)
2474 if (nIndex>0)
2475 rEndRow = pData[nIndex-1].nRow + 1;
2476 else
2477 rEndRow = 0;
2478 if (pMarkArray)
2480 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, TRUE );
2481 if (nMarkEnd>rEndRow)
2482 rEndRow = nMarkEnd;
2485 else
2487 rEndRow = pData[nIndex].nRow;
2488 if (pMarkArray)
2490 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, FALSE );
2491 if (nMarkEnd<rEndRow)
2492 rEndRow = nMarkEnd;
2496 return TRUE;
2498 else
2499 return FALSE;
2502 //------------------------------------------------------------------------
2504 // Laden / Speichern
2508 #if 0
2509 void ScAttrArray::Save( SvStream& /* rStream */ ) const
2511 #if SC_ROWLIMIT_STREAM_ACCESS
2512 #error address types changed!
2513 ScWriteHeader aHdr( rStream, 8 );
2515 ScDocumentPool* pDocPool = pDocument->GetPool();
2517 USHORT nSaveCount = nCount;
2518 SCROW nSaveMaxRow = pDocument->GetSrcMaxRow();
2519 if ( nSaveMaxRow != MAXROW )
2521 if ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow )
2523 pDocument->SetLostData(); // Warnung ausgeben
2525 --nSaveCount;
2526 while ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow );
2530 rStream << nSaveCount;
2532 const SfxPoolItem* pItem;
2533 for (SCSIZE i=0; i<nSaveCount; i++)
2535 rStream << Min( pData[i].nRow, nSaveMaxRow );
2537 const ScPatternAttr* pPattern = pData[i].pPattern;
2538 pDocPool->StoreSurrogate( rStream, pPattern );
2540 // FALSE, weil ATTR_CONDITIONAL (noch) nicht in Vorlagen:
2541 if (pPattern->GetItemSet().GetItemState(ATTR_CONDITIONAL,FALSE,&pItem) == SFX_ITEM_SET)
2542 pDocument->SetConditionalUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
2544 if (pPattern->GetItemSet().GetItemState(ATTR_VALIDDATA,FALSE,&pItem) == SFX_ITEM_SET)
2545 pDocument->SetValidationUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
2547 #endif // SC_ROWLIMIT_STREAM_ACCESS
2551 void ScAttrArray::Load( SvStream& /* rStream */ )
2553 #if SC_ROWLIMIT_STREAM_ACCESS
2554 #error address types changed!
2555 ScDocumentPool* pDocPool = pDocument->GetPool();
2557 ScReadHeader aHdr( rStream );
2559 USHORT nNewCount;
2560 rStream >> nNewCount;
2561 if ( nNewCount > MAXROW+1 ) // wuerde das Array zu gross?
2563 pDocument->SetLostData();
2564 rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
2565 return;
2568 Reset( pDocument->GetDefPattern(), FALSE ); // loeschen
2569 pData = new ScAttrEntry[nNewCount]; // neu anlegen
2570 for (SCSIZE i=0; i<nNewCount; i++)
2572 rStream >> pData[i].nRow;
2574 USHORT nWhich = ATTR_PATTERN;
2575 const ScPatternAttr* pNewPattern = (const ScPatternAttr*)
2576 pDocPool->LoadSurrogate( rStream, nWhich, ATTR_PATTERN );
2577 if (!pNewPattern)
2579 // da is was schiefgelaufen
2580 DBG_ERROR("ScAttrArray::Load: Surrogat nicht im Pool");
2581 pNewPattern = pDocument->GetDefPattern();
2583 ScDocumentPool::CheckRef( *pNewPattern );
2584 pData[i].pPattern = pNewPattern;
2586 // LoadSurrogate erhoeht auch die Ref
2588 nCount = nLimit = nNewCount;
2590 if ( nCount > 1 && pData[nCount-2].nRow >= MAXROW ) // faengt ein Attribut hinter MAXROW an?
2592 pDocument->SetLostData();
2593 rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
2594 return;
2597 if ( pDocument->GetSrcMaxRow() != MAXROW ) // Ende anpassen?
2599 // Ende immer auf MAXROW umsetzen (nur auf 32 Bit)
2601 DBG_ASSERT( pData[nCount-1].nRow == pDocument->GetSrcMaxRow(), "Attribut-Ende ?!?" );
2602 pData[nCount-1].nRow = MAXROW;
2604 #endif // SC_ROWLIMIT_STREAM_ACCESS
2606 #endif
2609 //UNUSED2008-05 void ScAttrArray::ConvertFontsAfterLoad()
2610 //UNUSED2008-05 {
2611 //UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter;
2612 //UNUSED2008-05 const ULONG nFlags = FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
2613 //UNUSED2008-05 SCSIZE nIndex = 0;
2614 //UNUSED2008-05 SCROW nThisRow = 0;
2615 //UNUSED2008-05
2616 //UNUSED2008-05 while ( nThisRow <= MAXROW )
2617 //UNUSED2008-05 {
2618 //UNUSED2008-05 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
2619 //UNUSED2008-05 const SfxPoolItem* pItem;
2620 //UNUSED2008-05 if( pOldPattern->GetItemSet().GetItemState( ATTR_FONT, FALSE, &pItem ) == SFX_ITEM_SET )
2621 //UNUSED2008-05 {
2622 //UNUSED2008-05 const SvxFontItem* pFontItem = (const SvxFontItem*) pItem;
2623 //UNUSED2008-05 const String& rOldName = pFontItem->GetFamilyName();
2624 //UNUSED2008-05 xFontConverter = CreateFontToSubsFontConverter( rOldName, nFlags );
2625 //UNUSED2008-05 if ( xFontConverter )
2626 //UNUSED2008-05 {
2627 //UNUSED2008-05 String aNewName( GetFontToSubsFontName( xFontConverter ) );
2628 //UNUSED2008-05 if ( aNewName != rOldName )
2629 //UNUSED2008-05 {
2630 //UNUSED2008-05 SCROW nAttrRow = pData[nIndex].nRow;
2631 //UNUSED2008-05 SvxFontItem aNewItem( pFontItem->GetFamily(), aNewName,
2632 //UNUSED2008-05 pFontItem->GetStyleName(), pFontItem->GetPitch(),
2633 //UNUSED2008-05 RTL_TEXTENCODING_DONTKNOW, ATTR_FONT );
2634 //UNUSED2008-05 ScPatternAttr aNewPattern( *pOldPattern );
2635 //UNUSED2008-05 aNewPattern.GetItemSet().Put( aNewItem );
2636 //UNUSED2008-05 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
2637 //UNUSED2008-05 Search( nThisRow, nIndex ); //! data changed
2638 //UNUSED2008-05 }
2639 //UNUSED2008-05 }
2640 //UNUSED2008-05 }
2641 //UNUSED2008-05 ++nIndex;
2642 //UNUSED2008-05 nThisRow = pData[nIndex-1].nRow+1;
2643 //UNUSED2008-05 }
2644 //UNUSED2008-05 }