update dev300-m57
[ooovba.git] / sc / source / core / data / attarray.cxx
blobe94f8e25821bd10fe2815d7c7c948c207af52972
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 (bAlloc)
177 nCount = nLimit = 1;
178 pData = new ScAttrEntry[1];
179 if (pData)
181 ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern);
182 pData[0].nRow = MAXROW;
183 pData[0].pPattern = pNewPattern;
186 else
188 nCount = nLimit = 0;
189 pData = NULL; // muss sofort wieder belegt werden !
195 BOOL ScAttrArray::Concat(SCSIZE nPos)
197 BOOL bRet = FALSE;
198 if (pData && (nPos < nCount))
200 if (nPos > 0)
202 if (pData[nPos - 1].pPattern == pData[nPos].pPattern)
204 pData[nPos - 1].nRow = pData[nPos].nRow;
205 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
206 memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry));
207 pData[nCount - 1].pPattern = NULL;
208 pData[nCount - 1].nRow = 0;
209 nCount--;
210 nPos--;
211 bRet = TRUE;
214 if (nPos + 1 < nCount)
216 if (pData[nPos + 1].pPattern == pData[nPos].pPattern)
218 pData[nPos].nRow = pData[nPos + 1].nRow;
219 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
220 memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry));
221 pData[nCount - 1].pPattern = NULL;
222 pData[nCount - 1].nRow = 0;
223 nCount--;
224 bRet = TRUE;
228 return bRet;
231 //------------------------------------------------------------------------
233 BOOL ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
235 long nLo = 0;
236 long nHi = static_cast<long>(nCount) - 1;
237 long nStartRow = 0;
238 long nEndRow = 0;
239 long i = 0;
240 BOOL bFound = (nCount == 1);
241 if (pData)
243 while ( !bFound && nLo <= nHi )
245 i = (nLo + nHi) / 2;
246 if (i > 0)
247 nStartRow = (long) pData[i - 1].nRow;
248 else
249 nStartRow = -1;
250 nEndRow = (long) pData[i].nRow;
251 if (nEndRow < (long) nRow)
252 nLo = ++i;
253 else
254 if (nStartRow >= (long) nRow)
255 nHi = --i;
256 else
257 bFound = TRUE;
260 else
261 bFound = FALSE;
263 if (bFound)
264 nIndex=(SCSIZE)i;
265 else
266 nIndex=0;
267 return bFound;
271 const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
273 SCSIZE i;
274 if (Search( nRow, i ))
275 return pData[i].pPattern;
276 else
277 return NULL;
281 const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
282 SCROW& rEndRow, SCROW nRow ) const
284 SCSIZE nIndex;
285 if ( Search( nRow, nIndex ) )
287 if ( nIndex > 0 )
288 rStartRow = pData[nIndex-1].nRow + 1;
289 else
290 rStartRow = 0;
291 rEndRow = pData[nIndex].nRow;
292 return pData[nIndex].pPattern;
294 return NULL;
297 //------------------------------------------------------------------------
299 void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, BOOL bPutToPool )
301 SetPatternArea( nRow, nRow, pPattern, bPutToPool );
304 void ScAttrArray::RemoveCellCharAttribs( SCROW nStartRow, SCROW nEndRow,
305 const ScPatternAttr* pPattern, ScEditDataArray* pDataArray )
307 for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
309 ScBaseCell* pCell;
310 pDocument->GetCell(nCol, nRow, nTab, pCell);
311 if (pCell && pCell->GetCellType() == CELLTYPE_EDIT)
313 EditTextObject* pOldData = NULL;
314 ScEditCell* pEditCell = static_cast<ScEditCell*>(pCell);
315 if (pDataArray)
316 pOldData = pEditCell->GetData()->Clone();
317 pEditCell->RemoveCharAttribs(*pPattern);
318 if (pDataArray)
320 EditTextObject* pNewData = pEditCell->GetData()->Clone();
321 pDataArray->AddItem(nTab, nCol, nRow, pOldData, pNewData);
327 void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern,
328 BOOL bPutToPool, ScEditDataArray* pDataArray )
330 if (ValidRow(nStartRow) && ValidRow(nEndRow))
332 if (bPutToPool)
333 pPattern = (const ScPatternAttr*) &pDocument->GetPool()->Put(*pPattern);
335 if ((nStartRow == 0) && (nEndRow == MAXROW))
336 Reset(pPattern);
337 else
339 SCSIZE nNeeded = nCount + 2;
340 if ( nLimit < nNeeded )
342 nLimit += SC_ATTRARRAY_DELTA;
343 if ( nLimit < nNeeded )
344 nLimit = nNeeded;
345 ScAttrEntry* pNewData = new ScAttrEntry[nLimit];
346 memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
347 delete[] pData;
348 pData = pNewData;
351 ScAddress aAdrStart( nCol, 0, nTab );
352 ScAddress aAdrEnd ( nCol, 0, nTab );
354 SCSIZE ni = 0; // number of entries in beginning
355 SCSIZE nx = 0; // track position
356 SCROW ns = 0; // start row of track position
357 if ( nStartRow > 0 )
359 // skip beginning
360 SCSIZE nIndex;
361 Search( nStartRow, nIndex );
362 ni = nIndex;
364 if ( ni > 0 )
366 nx = ni;
367 ns = pData[ni-1].nRow+1;
371 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
372 // oder bedingte Formate neu gesetzt oder geloescht werden
373 while ( ns <= nEndRow )
375 const SfxItemSet& rNewSet = pPattern->GetItemSet();
376 const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
378 BOOL bNumFormatChanged;
379 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
380 rNewSet, rOldSet ) )
382 aAdrStart.SetRow( Max(nStartRow,ns) );
383 aAdrEnd .SetRow( Min(nEndRow,pData[nx].nRow) );
384 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
385 #ifdef DBG_INVALIDATE
386 DBGOUTPUT("SetPatternArea");
387 #endif
389 if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
391 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
392 rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
393 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
394 rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
396 ns = pData[nx].nRow + 1;
397 nx++;
400 // continue modifying data array
402 SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert)
403 BOOL bCombined = FALSE;
404 BOOL bSplit = FALSE;
405 if ( nStartRow > 0 )
407 nInsert = MAXROWCOUNT;
408 if ( pData[ni].pPattern != pPattern )
410 if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
411 { // may be a split or a simple insert or just a shrink,
412 // row adjustment is done further down
413 if ( pData[ni].nRow > nEndRow )
414 bSplit = TRUE;
415 ni++;
416 nInsert = ni;
418 else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
419 nInsert = ni;
421 if ( ni > 0 && pData[ni-1].pPattern == pPattern )
422 { // combine
423 pData[ni-1].nRow = nEndRow;
424 nInsert = MAXROWCOUNT;
425 bCombined = TRUE;
428 else
429 nInsert = 0;
431 SCSIZE nj = ni; // stop position of range to replace
432 while ( nj < nCount && pData[nj].nRow <= nEndRow )
433 nj++;
434 if ( !bSplit )
436 if ( nj < nCount && pData[nj].pPattern == pPattern )
437 { // combine
438 if ( ni > 0 )
440 if ( pData[ni-1].pPattern == pPattern )
441 { // adjacent entries
442 pData[ni-1].nRow = pData[nj].nRow;
443 nj++;
445 else if ( ni == nInsert )
446 pData[ni-1].nRow = nStartRow - 1; // shrink
448 nInsert = MAXROWCOUNT;
449 bCombined = TRUE;
451 else if ( ni > 0 && ni == nInsert )
452 pData[ni-1].nRow = nStartRow - 1; // shrink
454 ScDocumentPool* pDocPool = pDocument->GetPool();
455 if ( bSplit )
456 { // duplicate splitted entry in pool
457 pDocPool->Put( *pData[ni-1].pPattern );
459 if ( ni < nj )
460 { // remove middle entries
461 for ( SCSIZE nk=ni; nk<nj; nk++)
462 { // remove entries from pool
463 pDocPool->Remove( *pData[nk].pPattern );
465 if ( !bCombined )
466 { // replace one entry
467 pData[ni].nRow = nEndRow;
468 pData[ni].pPattern = pPattern;
469 ni++;
470 nInsert = MAXROWCOUNT;
472 if ( ni < nj )
473 { // remove entries
474 memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
475 nCount -= nj - ni;
479 if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
480 { // insert or append new entry
481 if ( nInsert <= nCount )
483 if ( !bSplit )
484 memmove( pData + nInsert + 1, pData + nInsert,
485 (nCount - nInsert) * sizeof(ScAttrEntry) );
486 else
488 memmove( pData + nInsert + 2, pData + nInsert,
489 (nCount - nInsert) * sizeof(ScAttrEntry) );
490 pData[nInsert+1] = pData[nInsert-1];
491 nCount++;
494 if ( nInsert )
495 pData[nInsert-1].nRow = nStartRow - 1;
496 pData[nInsert].nRow = nEndRow;
497 pData[nInsert].pPattern = pPattern;
499 // Remove character attributes from these cells if the pattern
500 // is applied during normal session. We don't want to do this
501 // while importing document.
502 if (!pDocument->IsLoadingMedium())
503 RemoveCellCharAttribs(nStartRow, nEndRow, pPattern ,pDataArray);
505 nCount++;
509 // InfoBox(0, String(nCount) + String(" Eintraege") ).Execute();
511 #ifdef DBG_UTIL
512 TestData();
513 #endif
517 void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
519 if (ValidRow(nStartRow) && ValidRow(nEndRow))
521 SCSIZE nPos;
522 SCROW nStart=0;
523 if (!Search( nStartRow, nPos ))
525 DBG_ERROR("Search-Fehler");
526 return;
529 ScAddress aAdrStart( nCol, 0, nTab );
530 ScAddress aAdrEnd ( nCol, 0, nTab );
534 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
535 ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
536 pNewPattern->SetStyleSheet(pStyle);
537 SCROW nY1 = nStart;
538 SCROW nY2 = pData[nPos].nRow;
539 nStart = pData[nPos].nRow + 1;
541 if ( *pNewPattern == *pOldPattern )
543 // keep the original pattern (might be default)
544 // pNewPattern is deleted below
545 nPos++;
547 else if ( nY1 < nStartRow || nY2 > nEndRow )
549 if (nY1 < nStartRow) nY1=nStartRow;
550 if (nY2 > nEndRow) nY2=nEndRow;
551 SetPatternArea( nY1, nY2, pNewPattern, TRUE );
552 Search( nStart, nPos );
554 else
556 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
557 // bedingte Formate in Vorlagen gibt es (noch) nicht
559 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
560 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
562 BOOL bNumFormatChanged;
563 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
564 rNewSet, rOldSet ) )
566 aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
567 aAdrEnd .SetRow( pData[nPos].nRow );
568 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
569 #ifdef DBG_INVALIDATE
570 DBGOUTPUT("ApplyStyleArea");
571 #endif
574 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
575 pData[nPos].pPattern = (const ScPatternAttr*)
576 &pDocument->GetPool()->Put(*pNewPattern);
577 if (Concat(nPos))
578 Search(nStart, nPos);
579 else
580 nPos++;
582 delete pNewPattern;
584 while ((nStart <= nEndRow) && (nPos < nCount));
587 #ifdef DBG_UTIL
588 TestData();
589 #endif
593 // const wird weggecastet, weil es sonst
594 // zu ineffizient/kompliziert wird!
595 #define SET_LINECOLOR(dest,c) \
596 if ((dest)) \
598 ((SvxBorderLine*)(dest))->SetColor((c)); \
601 #define SET_LINE(dest,src) \
602 if ((dest)) \
604 SvxBorderLine* pCast = (SvxBorderLine*)(dest); \
605 pCast->SetOutWidth((src)->GetOutWidth()); \
606 pCast->SetInWidth ((src)->GetInWidth()); \
607 pCast->SetDistance((src)->GetDistance()); \
610 void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
611 const SvxBorderLine* pLine, BOOL bColorOnly )
613 if ( bColorOnly && !pLine )
614 return;
616 if (ValidRow(nStartRow) && ValidRow(nEndRow))
618 SCSIZE nPos;
619 SCROW nStart=0;
620 if (!Search( nStartRow, nPos ))
622 DBG_ERROR("Search-Fehler");
623 return;
628 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
629 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
630 const SfxPoolItem* pBoxItem = 0;
631 SfxItemState eState = rOldSet.GetItemState( ATTR_BORDER, TRUE, &pBoxItem );
632 const SfxPoolItem* pTLBRItem = 0;
633 SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, TRUE, &pTLBRItem );
634 const SfxPoolItem* pBLTRItem = 0;
635 SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, TRUE, &pBLTRItem );
637 if ( (SFX_ITEM_SET == eState) || (SFX_ITEM_SET == eTLBRState) || (SFX_ITEM_SET == eBLTRState) )
639 ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
640 SfxItemSet& rNewSet = pNewPattern->GetItemSet();
641 SCROW nY1 = nStart;
642 SCROW nY2 = pData[nPos].nRow;
644 SvxBoxItem* pNewBoxItem = pBoxItem ? (SvxBoxItem*)pBoxItem->Clone() : 0;
645 SvxLineItem* pNewTLBRItem = pTLBRItem ? (SvxLineItem*)pTLBRItem->Clone() : 0;
646 SvxLineItem* pNewBLTRItem = pBLTRItem ? (SvxLineItem*)pBLTRItem->Clone() : 0;
648 // Linienattribute holen und mit Parametern aktualisieren
650 if ( !pLine )
652 if( pNewBoxItem )
654 if ( pNewBoxItem->GetTop() ) pNewBoxItem->SetLine( NULL, BOX_LINE_TOP );
655 if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, BOX_LINE_BOTTOM );
656 if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( NULL, BOX_LINE_LEFT );
657 if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( NULL, BOX_LINE_RIGHT );
659 if( pNewTLBRItem && pNewTLBRItem->GetLine() )
660 pNewTLBRItem->SetLine( 0 );
661 if( pNewBLTRItem && pNewBLTRItem->GetLine() )
662 pNewBLTRItem->SetLine( 0 );
664 else
666 if ( bColorOnly )
668 Color aColor( pLine->GetColor() );
669 if( pNewBoxItem )
671 SET_LINECOLOR( pNewBoxItem->GetTop(), aColor );
672 SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor );
673 SET_LINECOLOR( pNewBoxItem->GetLeft(), aColor );
674 SET_LINECOLOR( pNewBoxItem->GetRight(), aColor );
676 if( pNewTLBRItem )
677 SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor );
678 if( pNewBLTRItem )
679 SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor );
681 else
683 if( pNewBoxItem )
685 SET_LINE( pNewBoxItem->GetTop(), pLine );
686 SET_LINE( pNewBoxItem->GetBottom(), pLine );
687 SET_LINE( pNewBoxItem->GetLeft(), pLine );
688 SET_LINE( pNewBoxItem->GetRight(), pLine );
690 if( pNewTLBRItem )
691 SET_LINE( pNewTLBRItem->GetLine(), pLine );
692 if( pNewBLTRItem )
693 SET_LINE( pNewBLTRItem->GetLine(), pLine );
696 if( pNewBoxItem ) rNewSet.Put( *pNewBoxItem );
697 if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem );
698 if( pNewBLTRItem ) rNewSet.Put( *pNewBLTRItem );
700 nStart = pData[nPos].nRow + 1;
702 if ( nY1 < nStartRow || nY2 > nEndRow )
704 if (nY1 < nStartRow) nY1=nStartRow;
705 if (nY2 > nEndRow) nY2=nEndRow;
706 SetPatternArea( nY1, nY2, pNewPattern, TRUE );
707 Search( nStart, nPos );
709 else
711 //! aus Pool loeschen?
712 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
713 pData[nPos].pPattern = (const ScPatternAttr*)
714 &pDocument->GetPool()->Put(*pNewPattern);
716 if (Concat(nPos))
717 Search(nStart, nPos);
718 else
719 nPos++;
721 delete pNewBoxItem;
722 delete pNewTLBRItem;
723 delete pNewBLTRItem;
724 delete pNewPattern;
726 else
728 nStart = pData[nPos].nRow + 1;
729 nPos++;
732 while ((nStart <= nEndRow) && (nPos < nCount));
736 #undef SET_LINECOLOR
737 #undef SET_LINE
740 void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache, ScEditDataArray* pDataArray )
742 #ifdef DBG_UTIL
743 TestData();
744 #endif
746 if (ValidRow(nStartRow) && ValidRow(nEndRow))
748 SCSIZE nPos;
749 SCROW nStart=0;
750 if (!Search( nStartRow, nPos ))
752 DBG_ERROR("Search-Fehler");
753 return;
756 ScAddress aAdrStart( nCol, 0, nTab );
757 ScAddress aAdrEnd ( nCol, 0, nTab );
761 const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
762 const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pCache->ApplyTo( *pOldPattern, TRUE );
763 ScDocumentPool::CheckRef( *pOldPattern );
764 ScDocumentPool::CheckRef( *pNewPattern );
765 if (pNewPattern != pOldPattern)
767 SCROW nY1 = nStart;
768 SCROW nY2 = pData[nPos].nRow;
769 nStart = pData[nPos].nRow + 1;
771 if ( nY1 < nStartRow || nY2 > nEndRow )
773 if (nY1 < nStartRow) nY1=nStartRow;
774 if (nY2 > nEndRow) nY2=nEndRow;
775 SetPatternArea( nY1, nY2, pNewPattern, false, pDataArray );
776 Search( nStart, nPos );
778 else
780 // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
782 const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
783 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
785 BOOL bNumFormatChanged;
786 if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
787 rNewSet, rOldSet ) )
789 aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
790 aAdrEnd .SetRow( pData[nPos].nRow );
791 pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
792 #ifdef DBG_INVALIDATE
793 DBGOUTPUT("ApplyCacheArea");
794 #endif
797 // bedingte Formate neu gesetzt oder geloescht ?
799 if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
801 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
802 rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
803 pDocument->ConditionalChanged( ((const SfxUInt32Item&)
804 rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
807 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
808 pData[nPos].pPattern = pNewPattern;
809 if (Concat(nPos))
810 Search(nStart, nPos);
811 else
812 ++nPos;
815 else
817 //!!!!!!!!!!!!!!!!!! mit diesem Remove gibt es Abstuerze (Calc1 Import)
818 //! pDocument->GetPool()->Remove(*pNewPattern);
819 nStart = pData[nPos].nRow + 1;
820 ++nPos;
823 while (nStart <= nEndRow);
826 #ifdef DBG_UTIL
827 TestData();
828 #endif
832 void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
834 const SfxPoolItem* pNewItem;
835 const SfxPoolItem* pOldItem;
836 for (USHORT nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
838 // pMergeSet hat keinen Parent
839 SfxItemState eOldState = rMergeSet.GetItemState( nId, FALSE, &pOldItem );
841 if ( eOldState == SFX_ITEM_DEFAULT ) // Default
843 SfxItemState eNewState = rSource.GetItemState( nId, TRUE, &pNewItem );
844 if ( eNewState == SFX_ITEM_SET )
846 if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
847 rMergeSet.InvalidateItem( nId );
850 else if ( eOldState == SFX_ITEM_SET ) // Item gesetzt
852 SfxItemState eNewState = rSource.GetItemState( nId, TRUE, &pNewItem );
853 if ( eNewState == SFX_ITEM_SET )
855 if ( pNewItem != pOldItem ) // beide gepuhlt
856 rMergeSet.InvalidateItem( nId );
858 else // Default
860 if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
861 rMergeSet.InvalidateItem( nId );
864 // Dontcare bleibt Dontcare
869 void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
870 ScMergePatternState& rState, BOOL bDeep ) const
872 if (ValidRow(nStartRow) && ValidRow(nEndRow))
874 SCSIZE nPos;
875 SCROW nStart=0;
876 if (!Search( nStartRow, nPos ))
878 DBG_ERROR("Search-Fehler");
879 return;
884 // gleiche Patterns muessen nicht mehrfach angesehen werden
886 const ScPatternAttr* pPattern = pData[nPos].pPattern;
887 if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
889 const SfxItemSet& rThisSet = pPattern->GetItemSet();
890 if (rState.pItemSet)
892 // (*ppSet)->MergeValues( rThisSet, FALSE );
893 // geht nicht, weil die Vorlagen nicht beruecksichtigt werden
895 if (bDeep)
896 lcl_MergeDeep( *rState.pItemSet, rThisSet );
897 else
898 rState.pItemSet->MergeValues( rThisSet, FALSE );
900 else
902 // erstes Pattern - in Set ohne Parent kopieren
903 rState.pItemSet = new SfxItemSet( *rThisSet.GetPool(), rThisSet.GetRanges() );
904 rState.pItemSet->Set( rThisSet, bDeep );
907 rState.pOld2 = rState.pOld1;
908 rState.pOld1 = pPattern;
911 nStart = pData[nPos].nRow + 1;
912 ++nPos;
914 while (nStart <= nEndRow);
920 // Umrandung zusammenbauen
922 BOOL lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
923 BYTE& rModified, const SvxBorderLine*& rpNew )
925 if (rModified == SC_LINE_DONTCARE)
926 return FALSE; // weiter geht's nicht
928 if (rModified == SC_LINE_EMPTY)
930 rModified = SC_LINE_SET;
931 rpNew = pNewLine;
932 return TRUE; // zum ersten mal gesetzt
935 if (pOldLine == pNewLine)
937 rpNew = pOldLine;
938 return FALSE;
941 if (pOldLine && pNewLine)
942 if (*pOldLine == *pNewLine)
944 rpNew = pOldLine;
945 return FALSE;
948 rModified = SC_LINE_DONTCARE;
949 rpNew = NULL;
950 return TRUE; // andere Linie -> dontcare
954 void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
955 ScLineFlags& rFlags, const ScPatternAttr* pPattern,
956 BOOL bLeft, SCCOL nDistRight, BOOL bTop, SCROW nDistBottom )
958 // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst:
959 const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
960 if ( rMerge.GetColMerge() == nDistRight + 1 )
961 nDistRight = 0;
962 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
963 nDistBottom = 0;
965 const SvxBoxItem* pCellFrame = (SvxBoxItem*) &pPattern->GetItemSet().Get( ATTR_BORDER );
966 const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft();
967 const SvxBorderLine* pRightAttr = pCellFrame->GetRight();
968 const SvxBorderLine* pTopAttr = pCellFrame->GetTop();
969 const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom();
970 const SvxBorderLine* pNew;
972 if (bTop)
974 if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
975 pLineOuter->SetLine( pNew, BOX_LINE_TOP );
977 else
979 if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew ))
980 pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
983 if (nDistBottom == 0)
985 if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew ))
986 pLineOuter->SetLine( pNew, BOX_LINE_BOTTOM );
988 else
990 if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
991 pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
994 if (bLeft)
996 if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
997 pLineOuter->SetLine( pNew, BOX_LINE_LEFT );
999 else
1001 if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew ))
1002 pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
1005 if (nDistRight == 0)
1007 if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew ))
1008 pLineOuter->SetLine( pNew, BOX_LINE_RIGHT );
1010 else
1012 if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew ))
1013 pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
1018 void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
1019 ScLineFlags& rFlags,
1020 SCROW nStartRow, SCROW nEndRow, BOOL bLeft, SCCOL nDistRight ) const
1022 const ScPatternAttr* pPattern;
1024 if (nStartRow == nEndRow)
1026 pPattern = GetPattern( nStartRow );
1027 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, TRUE, 0 );
1029 else
1031 pPattern = GetPattern( nStartRow );
1032 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, TRUE,
1033 nEndRow-nStartRow );
1035 SCSIZE nStartIndex;
1036 SCSIZE nEndIndex;
1037 Search( nStartRow+1, nStartIndex );
1038 Search( nEndRow-1, nEndIndex );
1039 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1041 pPattern = (ScPatternAttr*) pData[i].pPattern;
1042 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, FALSE,
1043 nEndRow - Min( pData[i].nRow, (SCROW)(nEndRow-1) ) );
1044 // nDistBottom hier immer > 0
1047 pPattern = GetPattern( nEndRow );
1048 lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, FALSE, 0 );
1053 // Rahmen anwenden
1056 // ApplyFrame - auf einen Eintrag im Array
1059 BOOL ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
1060 const SvxBoxInfoItem* pBoxInfoItem,
1061 SCROW nStartRow, SCROW nEndRow,
1062 BOOL bLeft, SCCOL nDistRight, BOOL bTop, SCROW nDistBottom )
1064 DBG_ASSERT( pBoxItem && pBoxInfoItem, "Linienattribute fehlen!" );
1066 const ScPatternAttr* pPattern = GetPattern( nStartRow );
1067 const SvxBoxItem* pOldFrame = (const SvxBoxItem*)
1068 &pPattern->GetItemSet().Get( ATTR_BORDER );
1070 // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst:
1071 const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
1072 if ( rMerge.GetColMerge() == nDistRight + 1 )
1073 nDistRight = 0;
1074 if ( rMerge.GetRowMerge() == nDistBottom + 1 )
1075 nDistBottom = 0;
1077 SvxBoxItem aNewFrame( *pOldFrame );
1079 if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
1080 aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
1081 BOX_LINE_LEFT );
1082 if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
1083 aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
1084 BOX_LINE_RIGHT );
1085 if ( bTop ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) )
1086 aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
1087 BOX_LINE_TOP );
1088 if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) )
1089 aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(),
1090 BOX_LINE_BOTTOM );
1092 if (aNewFrame == *pOldFrame)
1094 // nothing to do
1095 return FALSE;
1097 else
1099 SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
1100 ApplyCacheArea( nStartRow, nEndRow, &aCache );
1102 /* ScPatternAttr* pNewPattern = (ScPatternAttr*) pPattern->Clone();
1103 pNewPattern->GetItemSet().Put( aNewFrame );
1104 SetPatternArea( nStartRow, nEndRow, pNewPattern, TRUE );
1106 return TRUE;
1111 void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
1112 SCROW nStartRow, SCROW nEndRow, BOOL bLeft, SCCOL nDistRight )
1114 if (nStartRow == nEndRow)
1115 ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, TRUE, 0 );
1116 else
1118 ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
1119 TRUE, nEndRow-nStartRow );
1121 if ( nEndRow > nStartRow+1 ) // innerer Teil vorhanden?
1123 SCSIZE nStartIndex;
1124 SCSIZE nEndIndex;
1125 Search( nStartRow+1, nStartIndex );
1126 Search( nEndRow-1, nEndIndex );
1127 SCROW nTmpStart = nStartRow+1;
1128 SCROW nTmpEnd;
1129 for (SCSIZE i=nStartIndex; i<=nEndIndex;)
1131 nTmpEnd = Min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) );
1132 BOOL bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd,
1133 bLeft, nDistRight, FALSE, nEndRow-nTmpEnd );
1134 nTmpStart = nTmpEnd+1;
1135 if (bChanged)
1137 Search(nTmpStart, i);
1138 Search(nEndRow-1, nEndIndex);
1140 else
1141 i++;
1145 ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, FALSE, 0 );
1150 long lcl_LineSize( const SvxBorderLine& rLine )
1152 // nur eine Linie -> halbe Breite, min. 20
1153 // doppelte Linie -> halber Abstand + eine Linie (je min. 20)
1155 long nTotal = 0;
1156 USHORT nWidth = Max( rLine.GetOutWidth(), rLine.GetInWidth() );
1157 USHORT nDist = rLine.GetDistance();
1158 if (nDist)
1160 DBG_ASSERT( rLine.GetOutWidth() && rLine.GetInWidth(),
1161 "Linie hat Abstand, aber nur eine Breite ???" );
1163 // nTotal += ( nDist > 40 ) ? ( nDist / 2 ) : 20;
1164 nTotal += ( nDist > 20 ) ? nDist : 20;
1165 nTotal += ( nWidth > 20 ) ? nWidth : 20;
1167 else if (nWidth)
1168 // nTotal += ( nWidth > 40 ) ? ( nWidth / 2 ) : 20;
1169 nTotal += ( nWidth > 20 ) ? nWidth : 20;
1171 //! auch halbieren ???
1173 return nTotal;
1177 BOOL ScAttrArray::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
1178 BOOL bLeft, BOOL bRight ) const
1180 SCSIZE nStartIndex;
1181 SCSIZE nEndIndex;
1182 Search( nRow1, nStartIndex );
1183 Search( nRow2, nEndIndex );
1184 BOOL bFound = FALSE;
1186 const SvxBoxItem* pItem = 0;
1187 const SvxBorderLine* pLine = 0;
1188 long nCmp;
1190 // oben
1192 pItem = (const SvxBoxItem*) &pData[nStartIndex].pPattern->GetItem(ATTR_BORDER);
1193 pLine = pItem->GetTop();
1194 if (pLine)
1196 nCmp = lcl_LineSize(*pLine);
1197 if ( nCmp > rSizes.Top() )
1198 rSizes.Top() = nCmp;
1199 bFound = TRUE;
1202 // unten
1204 if ( nEndIndex != nStartIndex )
1205 pItem = (const SvxBoxItem*) &pData[nEndIndex].pPattern->GetItem(ATTR_BORDER);
1206 pLine = pItem->GetBottom();
1207 if (pLine)
1209 nCmp = lcl_LineSize(*pLine);
1210 if ( nCmp > rSizes.Bottom() )
1211 rSizes.Bottom() = nCmp;
1212 bFound = TRUE;
1215 if ( bLeft || bRight )
1216 for ( SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1218 pItem = (const SvxBoxItem*) &pData[i].pPattern->GetItem(ATTR_BORDER);
1220 // links
1222 if (bLeft)
1224 pLine = pItem->GetLeft();
1225 if (pLine)
1227 nCmp = lcl_LineSize(*pLine);
1228 if ( nCmp > rSizes.Left() )
1229 rSizes.Left() = nCmp;
1230 bFound = TRUE;
1234 // rechts
1236 if (bRight)
1238 pLine = pItem->GetRight();
1239 if (pLine)
1241 nCmp = lcl_LineSize(*pLine);
1242 if ( nCmp > rSizes.Right() )
1243 rSizes.Right() = nCmp;
1244 bFound = TRUE;
1249 return bFound;
1252 // Testen, ob Bereich bestimmtes Attribut enthaelt
1254 BOOL ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, USHORT nMask ) const
1256 SCSIZE nStartIndex;
1257 SCSIZE nEndIndex;
1258 Search( nRow1, nStartIndex );
1259 Search( nRow2, nEndIndex );
1260 BOOL bFound = FALSE;
1262 for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
1264 const ScPatternAttr* pPattern = pData[i].pPattern;
1265 if ( nMask & HASATTR_MERGED )
1267 const ScMergeAttr* pMerge =
1268 (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1269 if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
1270 bFound = TRUE;
1272 if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) )
1274 const ScMergeFlagAttr* pMergeFlag =
1275 (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG );
1276 if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() )
1277 bFound = TRUE;
1278 if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() )
1279 bFound = TRUE;
1280 if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() )
1281 bFound = TRUE;
1283 if ( nMask & HASATTR_LINES )
1285 const SvxBoxItem* pBox =
1286 (const SvxBoxItem*) &pPattern->GetItem( ATTR_BORDER );
1287 if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
1288 bFound = TRUE;
1290 if ( nMask & HASATTR_SHADOW )
1292 const SvxShadowItem* pShadow =
1293 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1294 if ( pShadow->GetLocation() != SVX_SHADOW_NONE )
1295 bFound = TRUE;
1297 if ( nMask & HASATTR_CONDITIONAL )
1299 const SfxUInt32Item* pConditional =
1300 (const SfxUInt32Item*) &pPattern->GetItem( ATTR_CONDITIONAL );
1301 if ( pConditional->GetValue() != 0 )
1302 bFound = TRUE;
1304 if ( nMask & HASATTR_PROTECTED )
1306 const ScProtectionAttr* pProtect =
1307 (const ScProtectionAttr*) &pPattern->GetItem( ATTR_PROTECTION );
1308 if ( pProtect->GetProtection() || pProtect->GetHideCell() )
1309 bFound = TRUE;
1311 if ( nMask & HASATTR_ROTATE )
1313 const SfxInt32Item* pRotate =
1314 (const SfxInt32Item*) &pPattern->GetItem( ATTR_ROTATE_VALUE );
1315 // 90 or 270 degrees is former SvxOrientationItem - only look for other values
1316 // (see ScPatternAttr::GetCellOrientation)
1317 INT32 nAngle = pRotate->GetValue();
1318 if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
1319 bFound = TRUE;
1321 if ( nMask & HASATTR_NEEDHEIGHT )
1323 if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
1324 bFound = TRUE;
1325 else if (((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue())
1326 bFound = TRUE;
1327 else if ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
1328 GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK)
1329 bFound = TRUE;
1330 else if (((const SfxUInt32Item&)pPattern->GetItem( ATTR_CONDITIONAL )).GetValue())
1331 bFound = TRUE;
1332 else if (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue())
1333 bFound = TRUE;
1335 if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) )
1337 const SvxShadowItem* pShadow =
1338 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1339 SvxShadowLocation eLoc = pShadow->GetLocation();
1340 if ( nMask & HASATTR_SHADOW_RIGHT )
1341 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1342 bFound = TRUE;
1343 if ( nMask & HASATTR_SHADOW_DOWN )
1344 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1345 bFound = TRUE;
1347 if ( nMask & HASATTR_RTL )
1349 const SvxFrameDirectionItem& rDirection =
1350 (const SvxFrameDirectionItem&) pPattern->GetItem( ATTR_WRITINGDIR );
1351 if ( rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP )
1352 bFound = TRUE;
1354 if ( nMask & HASATTR_RIGHTORCENTER )
1356 // called only if the sheet is LTR, so physical=logical alignment can be assumed
1357 SvxCellHorJustify eHorJust = (SvxCellHorJustify)
1358 ((const SvxHorJustifyItem&) pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
1359 if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER )
1360 bFound = TRUE;
1364 return bFound;
1367 // Bereich um evtl. enthaltene Zusammenfassungen erweitern
1368 // und evtl. MergeFlag anpassen (bRefresh)
1370 BOOL ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
1371 SCCOL& rPaintCol, SCROW& rPaintRow,
1372 BOOL bRefresh, BOOL bAttrs )
1374 const ScPatternAttr* pPattern;
1375 const ScMergeAttr* pItem;
1376 SCSIZE nStartIndex;
1377 SCSIZE nEndIndex;
1378 Search( nStartRow, nStartIndex );
1379 Search( nEndRow, nEndIndex );
1380 BOOL bFound = FALSE;
1382 for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
1384 pPattern = pData[i].pPattern;
1385 pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1386 SCsCOL nCountX = pItem->GetColMerge();
1387 SCsROW nCountY = pItem->GetRowMerge();
1388 if (nCountX>1 || nCountY>1)
1390 SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0;
1391 SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1392 SCROW nMergeEndRow = nThisRow + nCountY - 1;
1393 if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL)
1394 rPaintCol = nMergeEndCol;
1395 if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW)
1396 rPaintRow = nMergeEndRow;
1397 bFound = TRUE;
1399 if (bAttrs)
1401 const SvxShadowItem* pShadow =
1402 (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
1403 SvxShadowLocation eLoc = pShadow->GetLocation();
1404 if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1405 if ( nMergeEndCol+1 > rPaintCol && nMergeEndCol < MAXCOL )
1406 rPaintCol = nMergeEndCol+1;
1407 if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
1408 if ( nMergeEndRow+1 > rPaintRow && nMergeEndRow < MAXROW )
1409 rPaintRow = nMergeEndRow+1;
1412 if (bRefresh)
1414 if ( nMergeEndCol > nThisCol )
1415 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow,
1416 nTab, SC_MF_HOR );
1417 if ( nMergeEndRow > nThisRow )
1418 pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
1419 nTab, SC_MF_VER );
1420 if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
1421 pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
1422 nTab, SC_MF_HOR | SC_MF_VER );
1424 Search( nThisRow, i ); // Daten wurden veraendert
1425 Search( nStartRow, nStartIndex );
1426 Search( nEndRow, nEndIndex );
1431 return bFound;
1435 BOOL ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
1437 BOOL bFound = FALSE;
1438 const ScPatternAttr* pPattern;
1439 const ScMergeAttr* pItem;
1440 SCSIZE nIndex;
1442 Search( nStartRow, nIndex );
1443 SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1444 if (nThisStart < nStartRow)
1445 nThisStart = nStartRow;
1447 while ( nThisStart <= nEndRow )
1449 SCROW nThisEnd = pData[nIndex].nRow;
1450 if (nThisEnd > nEndRow)
1451 nThisEnd = nEndRow;
1453 pPattern = pData[nIndex].pPattern;
1454 pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
1455 SCsCOL nCountX = pItem->GetColMerge();
1456 SCsROW nCountY = pItem->GetRowMerge();
1457 if (nCountX>1 || nCountY>1)
1459 const ScMergeAttr* pAttr = (const ScMergeAttr*)
1460 &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
1461 const ScMergeFlagAttr* pFlagAttr = (const ScMergeFlagAttr*)
1462 &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG );
1464 DBG_ASSERT( nCountY==1 || nThisStart==nThisEnd, "was'n hier los?" );
1466 SCCOL nThisCol = nCol;
1467 SCCOL nMergeEndCol = nThisCol + nCountX - 1;
1468 SCROW nMergeEndRow = nThisEnd + nCountY - 1;
1470 //! ApplyAttr fuer Bereiche !!!
1472 for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
1473 pDocument->ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
1475 ScPatternAttr* pNewPattern = new ScPatternAttr( pDocument->GetPool() );
1476 SfxItemSet* pSet = &pNewPattern->GetItemSet();
1477 pSet->Put( *pFlagAttr );
1478 pDocument->ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
1479 nTab, *pNewPattern );
1480 delete pNewPattern;
1482 Search( nThisEnd, nIndex ); // Daten wurden veraendert !!!
1485 ++nIndex;
1486 if ( nIndex < nCount )
1487 nThisStart = pData[nIndex-1].nRow+1;
1488 else
1489 nThisStart = MAXROW+1; // Ende
1492 return bFound;
1495 // Bereich loeschen, aber Merge-Flags stehenlassen
1497 void ScAttrArray::DeleteAreaSafe(SCROW nStartRow, SCROW nEndRow)
1499 SetPatternAreaSafe( nStartRow, nEndRow, pDocument->GetDefPattern(), TRUE );
1503 void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
1504 const ScPatternAttr* pWantedPattern, BOOL bDefault )
1506 const ScPatternAttr* pOldPattern;
1507 const ScMergeFlagAttr* pItem;
1509 SCSIZE nIndex;
1510 SCROW nRow;
1511 SCROW nThisRow;
1512 BOOL bFirstUse = TRUE;
1514 Search( nStartRow, nIndex );
1515 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1516 while ( nThisRow <= nEndRow )
1518 pOldPattern = pData[nIndex].pPattern;
1519 if (pOldPattern != pWantedPattern) //! else-Zweig ?
1521 if (nThisRow < nStartRow) nThisRow = nStartRow;
1522 nRow = pData[nIndex].nRow;
1523 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1524 pItem = (const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG );
1526 if (pItem->IsOverlapped() || pItem->HasAutoFilter())
1528 // #108045# default-constructing a ScPatternAttr for DeleteArea doesn't work
1529 // because it would have no cell style information.
1530 // Instead, the document's GetDefPattern is copied. Since it is passed as
1531 // pWantedPattern, no special treatment of default is needed here anymore.
1532 ScPatternAttr* pNewPattern = new ScPatternAttr( *pWantedPattern );
1533 SfxItemSet* pSet = &pNewPattern->GetItemSet();
1534 pSet->Put( *pItem );
1535 SetPatternArea( nThisRow, nAttrRow, pNewPattern, TRUE );
1536 delete pNewPattern;
1538 else
1540 if ( !bDefault )
1542 if (bFirstUse)
1543 bFirstUse = FALSE;
1544 else
1545 pDocument->GetPool()->Put( *pWantedPattern ); // im Pool ist es schon!
1547 SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
1550 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1553 ++nIndex;
1554 nThisRow = pData[nIndex-1].nRow+1;
1559 BOOL ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, INT16 nFlags )
1561 const ScPatternAttr* pOldPattern;
1563 INT16 nOldValue;
1564 SCSIZE nIndex;
1565 SCROW nRow;
1566 SCROW nThisRow;
1567 BOOL bChanged = FALSE;
1569 Search( nStartRow, nIndex );
1570 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1571 if (nThisRow < nStartRow) nThisRow = nStartRow;
1573 while ( nThisRow <= nEndRow )
1575 pOldPattern = pData[nIndex].pPattern;
1576 nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1577 if ( (nOldValue | nFlags) != nOldValue )
1579 nRow = pData[nIndex].nRow;
1580 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1581 ScPatternAttr aNewPattern(*pOldPattern);
1582 aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
1583 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
1584 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1585 bChanged = TRUE;
1588 ++nIndex;
1589 nThisRow = pData[nIndex-1].nRow+1;
1592 return bChanged;
1596 BOOL ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, INT16 nFlags )
1598 const ScPatternAttr* pOldPattern;
1600 INT16 nOldValue;
1601 SCSIZE nIndex;
1602 SCROW nRow;
1603 SCROW nThisRow;
1604 BOOL bChanged = FALSE;
1606 Search( nStartRow, nIndex );
1607 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1608 if (nThisRow < nStartRow) nThisRow = nStartRow;
1610 while ( nThisRow <= nEndRow )
1612 pOldPattern = pData[nIndex].pPattern;
1613 nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
1614 if ( (nOldValue & ~nFlags) != nOldValue )
1616 nRow = pData[nIndex].nRow;
1617 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1618 ScPatternAttr aNewPattern(*pOldPattern);
1619 aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
1620 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
1621 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1622 bChanged = TRUE;
1625 ++nIndex;
1626 nThisRow = pData[nIndex-1].nRow+1;
1629 return bChanged;
1633 void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const USHORT* pWhich )
1635 const ScPatternAttr* pOldPattern;
1637 SCSIZE nIndex;
1638 SCROW nRow;
1639 SCROW nThisRow;
1641 Search( nStartRow, nIndex );
1642 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1643 if (nThisRow < nStartRow) nThisRow = nStartRow;
1645 while ( nThisRow <= nEndRow )
1647 pOldPattern = pData[nIndex].pPattern;
1648 if ( pOldPattern->HasItemsSet( pWhich ) )
1650 ScPatternAttr aNewPattern(*pOldPattern);
1651 aNewPattern.ClearItems( pWhich );
1653 nRow = pData[nIndex].nRow;
1654 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
1655 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
1656 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
1659 ++nIndex;
1660 nThisRow = pData[nIndex-1].nRow+1;
1665 void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, BOOL bIncrement )
1667 SCSIZE nIndex;
1668 Search( nStartRow, nIndex );
1669 SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
1670 if (nThisStart < nStartRow) nThisStart = nStartRow;
1672 while ( nThisStart <= nEndRow )
1674 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
1675 const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
1676 const SfxPoolItem* pItem;
1678 BOOL bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, FALSE, &pItem ) != SFX_ITEM_SET
1679 || ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT );
1680 USHORT nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue();
1681 USHORT nNewValue = nOldValue;
1682 if ( bIncrement )
1684 if ( nNewValue < SC_MAX_INDENT )
1686 nNewValue += SC_INDENT_STEP;
1687 if ( nNewValue > SC_MAX_INDENT ) nNewValue = SC_MAX_INDENT;
1690 else
1692 if ( nNewValue > 0 )
1694 if ( nNewValue > SC_INDENT_STEP )
1695 nNewValue -= SC_INDENT_STEP;
1696 else
1697 nNewValue = 0;
1701 if ( bNeedJust || nNewValue != nOldValue )
1703 SCROW nThisEnd = pData[nIndex].nRow;
1704 SCROW nAttrRow = Min( nThisEnd, nEndRow );
1705 ScPatternAttr aNewPattern(*pOldPattern);
1706 aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) );
1707 if ( bNeedJust )
1708 aNewPattern.GetItemSet().Put(
1709 SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
1710 SetPatternArea( nThisStart, nAttrRow, &aNewPattern, TRUE );
1712 nThisStart = nThisEnd + 1;
1713 Search( nThisStart, nIndex ); // Daten wurden veraendert !!!
1715 else
1717 nThisStart = pData[nIndex].nRow + 1; // weiterzaehlen...
1718 ++nIndex;
1724 SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, BOOL bUp ) const
1726 long nRet = nRow;
1727 if (VALIDROW(nRow))
1729 SCSIZE nIndex;
1730 Search(nRow, nIndex);
1731 while (((const ScProtectionAttr&)pData[nIndex].pPattern->
1732 GetItem(ATTR_PROTECTION)).GetProtection())
1734 if (bUp)
1736 if (nIndex==0)
1737 return -1; // nichts gefunden
1738 --nIndex;
1739 nRet = pData[nIndex].nRow;
1741 else
1743 nRet = pData[nIndex].nRow+1;
1744 ++nIndex;
1745 if (nIndex>=nCount)
1746 return MAXROW+1; // nichts gefunden
1750 return nRet;
1753 void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBoolRowSegments& rUsedRows, bool bReset )
1755 SCROW nStart = 0;
1756 SCSIZE nPos = 0;
1757 while (nPos < nCount)
1759 SCROW nEnd = pData[nPos].nRow;
1760 if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
1762 // for (SCROW nRow = nStart; nRow <= nEnd; nRow++)
1763 // pUsed[nRow] = TRUE;
1765 rUsedRows.setTrue(nStart, nEnd);
1767 if (bReset)
1769 ScPatternAttr* pNewPattern = new ScPatternAttr(*pData[nPos].pPattern);
1770 pDocument->GetPool()->Remove(*pData[nPos].pPattern);
1771 pNewPattern->SetStyleSheet( (ScStyleSheet*)
1772 pDocument->GetStyleSheetPool()->
1773 Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD),
1774 SFX_STYLE_FAMILY_PARA,
1775 SFXSTYLEBIT_AUTO | SCSTYLEBIT_STANDARD ) );
1776 pData[nPos].pPattern = (const ScPatternAttr*)
1777 &pDocument->GetPool()->Put(*pNewPattern);
1778 delete pNewPattern;
1780 if (Concat(nPos))
1782 Search(nStart, nPos);
1783 --nPos; // wegen ++ am Ende
1787 nStart = nEnd + 1;
1788 ++nPos;
1793 BOOL ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
1794 BOOL bGatherAllStyles ) const
1796 BOOL bIsUsed = FALSE;
1797 SCSIZE nPos = 0;
1799 while ( nPos < nCount )
1801 const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet();
1802 if ( pStyle )
1804 pStyle->SetUsage( ScStyleSheet::USED );
1805 if ( pStyle == &rStyle )
1807 if ( !bGatherAllStyles )
1808 return TRUE;
1809 bIsUsed = TRUE;
1812 nPos++;
1815 return bIsUsed;
1819 BOOL ScAttrArray::IsEmpty() const
1821 if (nCount == 1)
1823 if ( pData[0].pPattern != pDocument->GetDefPattern() )
1824 return FALSE;
1825 else
1826 return TRUE;
1828 else
1829 return FALSE;
1833 //UNUSED2008-05 SCROW ScAttrArray::GetFirstEntryPos() const
1834 //UNUSED2008-05 {
1835 //UNUSED2008-05 DBG_ASSERT( nCount, "nCount = 0" );
1836 //UNUSED2008-05
1837 //UNUSED2008-05 if ( pData[0].pPattern != pDocument->GetDefPattern() )
1838 //UNUSED2008-05 return 0;
1839 //UNUSED2008-05 else
1840 //UNUSED2008-05 {
1841 //UNUSED2008-05 if (nCount==1)
1842 //UNUSED2008-05 return 0; // leer
1843 //UNUSED2008-05 else
1844 //UNUSED2008-05 return pData[0].nRow + 1;
1845 //UNUSED2008-05 }
1846 //UNUSED2008-05 }
1847 //UNUSED2008-05
1848 //UNUSED2008-05
1849 //UNUSED2008-05 SCROW ScAttrArray::GetLastEntryPos( BOOL bIncludeBottom ) const
1850 //UNUSED2008-05 {
1851 //UNUSED2008-05 DBG_ASSERT( nCount, "nCount == 0" );
1852 //UNUSED2008-05
1853 //UNUSED2008-05 if (bIncludeBottom)
1854 //UNUSED2008-05 bIncludeBottom = ( pData[nCount-1].pPattern != pDocument->GetDefPattern() );
1855 //UNUSED2008-05
1856 //UNUSED2008-05 if (bIncludeBottom)
1857 //UNUSED2008-05 return MAXROW;
1858 //UNUSED2008-05 else
1859 //UNUSED2008-05 {
1860 //UNUSED2008-05 if (nCount<=1)
1861 //UNUSED2008-05 return 0; // leer
1862 //UNUSED2008-05 else
1863 //UNUSED2008-05 return pData[nCount-2].nRow;
1864 //UNUSED2008-05 }
1865 //UNUSED2008-05 }
1868 BOOL ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
1870 DBG_ASSERT( nCount, "nCount == 0" );
1872 BOOL bFound = FALSE;
1873 SCSIZE nStart = 0;
1875 // Skip first entry if more than 1 row.
1876 // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
1878 SCSIZE nVisStart = 1;
1879 while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) )
1880 ++nVisStart;
1881 if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 ) // more than 1 row?
1882 nStart = nVisStart;
1884 while ( nStart < nCount && !bFound )
1886 if ( pData[nStart].pPattern->IsVisible() )
1888 rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0;
1889 bFound = TRUE;
1891 else
1892 ++nStart;
1895 return bFound;
1898 // size (rows) of a range of attributes after cell content where the search is stopped
1899 // (more than a default page size, 2*42 because it's as good as any number)
1901 const SCROW SC_VISATTR_STOP = 84;
1903 BOOL ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
1905 // #i30830# changed behavior:
1906 // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
1907 // below the last content cell
1909 if ( nLastData == MAXROW )
1911 rLastRow = MAXROW; // can't look for attributes below MAXROW
1912 return TRUE;
1915 BOOL bFound = FALSE;
1917 // loop backwards from the end instead of using Search, assuming that
1918 // there usually aren't many attributes below the last cell
1920 SCSIZE nPos = nCount;
1921 while ( nPos > 0 && pData[nPos-1].nRow > nLastData )
1923 SCSIZE nEndPos = nPos - 1;
1924 SCSIZE nStartPos = nEndPos; // find range of visually equal formats
1925 while ( nStartPos > 0 &&
1926 pData[nStartPos-1].nRow > nLastData &&
1927 pData[nStartPos-1].pPattern->IsVisibleEqual(*pData[nStartPos].pPattern) )
1928 --nStartPos;
1930 SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos-1].nRow + 1 ) : 0;
1931 if ( nAttrStartRow <= nLastData )
1932 nAttrStartRow = nLastData + 1;
1933 SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
1934 if ( nAttrSize >= SC_VISATTR_STOP )
1936 bFound = FALSE; // ignore this range and below
1938 else if ( !bFound && pData[nEndPos].pPattern->IsVisible() )
1940 rLastRow = pData[nEndPos].nRow;
1941 bFound = TRUE;
1944 nPos = nStartPos; // look further from the top of the range
1947 return bFound;
1951 BOOL ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
1953 SCSIZE nIndex;
1954 Search( nStartRow, nIndex );
1955 SCROW nThisStart = nStartRow;
1956 BOOL bFound = FALSE;
1957 while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
1959 if ( pData[nIndex].pPattern->IsVisible() )
1960 bFound = TRUE;
1962 nThisStart = pData[nIndex].nRow + 1;
1963 ++nIndex;
1966 return bFound;
1970 BOOL ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
1971 SCROW nStartRow, SCROW nEndRow ) const
1973 BOOL bEqual = TRUE;
1974 SCSIZE nThisPos = 0;
1975 SCSIZE nOtherPos = 0;
1976 if ( nStartRow > 0 )
1978 Search( nStartRow, nThisPos );
1979 rOther.Search( nStartRow, nOtherPos );
1982 while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
1984 SCROW nThisRow = pData[nThisPos].nRow;
1985 SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
1986 const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
1987 const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
1988 bEqual = ( pThisPattern == pOtherPattern ||
1989 pThisPattern->IsVisibleEqual(*pOtherPattern) );
1991 if ( nThisRow >= nOtherRow )
1993 if ( nOtherRow >= nEndRow ) break;
1994 ++nOtherPos;
1996 if ( nThisRow <= nOtherRow )
1998 if ( nThisRow >= nEndRow ) break;
1999 ++nThisPos;
2003 return bEqual;
2007 BOOL ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
2009 //! mit IsVisibleEqual zusammenfassen?
2011 BOOL bEqual = TRUE;
2012 SCSIZE nThisPos = 0;
2013 SCSIZE nOtherPos = 0;
2014 if ( nStartRow > 0 )
2016 Search( nStartRow, nThisPos );
2017 rOther.Search( nStartRow, nOtherPos );
2020 while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
2022 SCROW nThisRow = pData[nThisPos].nRow;
2023 SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
2024 const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
2025 const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
2026 bEqual = ( pThisPattern == pOtherPattern );
2028 if ( nThisRow >= nOtherRow )
2030 if ( nOtherRow >= nEndRow ) break;
2031 ++nOtherPos;
2033 if ( nThisRow <= nOtherRow )
2035 if ( nThisRow >= nEndRow ) break;
2036 ++nThisPos;
2040 return bEqual;
2044 BOOL ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
2046 // horizontal zusammengefasste duerfen nicht herausgeschoben werden
2047 // (ob die ganze Zusammenfassung betroffen ist, ist hier nicht zu erkennen)
2049 BOOL bTest = TRUE;
2050 if (!IsEmpty())
2052 SCSIZE nIndex = 0;
2053 if ( nStartRow > 0 )
2054 Search( nStartRow, nIndex );
2056 for ( ; nIndex < nCount; nIndex++ )
2058 if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern->
2059 GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
2061 bTest = FALSE; // darf nicht herausgeschoben werden
2062 break;
2064 if ( pData[nIndex].nRow >= nEndRow ) // Ende des Bereichs
2065 break;
2068 return bTest;
2072 BOOL ScAttrArray::TestInsertRow( SCSIZE nSize ) const
2074 // wenn die erste herausgeschobene Zeile vertikal ueberlappt ist,
2075 // wuerde eine kaputte Zusammenfassung uebrigbleiben
2077 if (pData)
2079 // MAXROW + 1 - nSize = erste herausgeschobene Zeile
2081 SCSIZE nFirstLost = nCount-1;
2082 while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
2083 --nFirstLost;
2085 if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern->
2086 GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
2087 return FALSE;
2090 return TRUE;
2094 void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
2096 if (!pData)
2097 return;
2099 SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // Vorgaenger erweitern
2100 SCSIZE nIndex;
2101 Search( nSearch, nIndex );
2103 // ein gesetztes ScMergeAttr darf nicht ausgedehnt werden
2104 // (darum hinterher wieder loeschen)
2106 BOOL bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
2108 SCSIZE nRemove = 0;
2109 SCSIZE i;
2110 for (i = nIndex; i < nCount-1; i++)
2112 SCROW nNew = pData[i].nRow + nSize;
2113 if ( nNew >= MAXROW ) // Ende erreicht ?
2115 nNew = MAXROW;
2116 if (!nRemove)
2117 nRemove = i+1; // folgende loeschen
2119 pData[i].nRow = nNew;
2122 // muessen Eintraege am Ende geloescht werden?
2124 if (nRemove && nRemove < nCount)
2125 DeleteRange( nRemove, nCount-1 );
2127 if (bDoMerge) // ausgedehntes ScMergeAttr wieder reparieren
2129 //! ApplyAttr fuer Bereiche !!!
2131 const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
2132 for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
2133 pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
2135 // im eingefuegten Bereich ist nichts zusammengefasst
2138 // Don't duplicate the merge flags in the inserted row.
2139 RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_ALL );
2143 void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
2145 if (pData)
2147 BOOL bFirst=TRUE;
2148 SCSIZE nStartIndex = 0;
2149 SCSIZE nEndIndex = 0;
2150 SCSIZE i;
2152 for ( i = 0; i < nCount-1; i++)
2153 if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
2155 if (bFirst)
2157 nStartIndex = i;
2158 bFirst = FALSE;
2160 nEndIndex = i;
2162 if (!bFirst)
2164 SCROW nStart;
2165 if (nStartIndex==0)
2166 nStart = 0;
2167 else
2168 nStart = pData[nStartIndex-1].nRow + 1;
2170 if (nStart < nStartRow)
2172 pData[nStartIndex].nRow = nStartRow - 1;
2173 ++nStartIndex;
2175 if (nEndIndex >= nStartIndex)
2177 DeleteRange( nStartIndex, nEndIndex );
2178 if (nStartIndex > 0)
2179 if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern )
2180 DeleteRange( nStartIndex-1, nStartIndex-1 );
2183 for (i = 0; i < nCount-1; i++)
2184 if (pData[i].nRow >= nStartRow)
2185 pData[i].nRow -= nSize;
2187 // unten nicht Default-Pattern nachschieben, um Druckbereiche erkennen zu koennen
2188 // stattdessen nur Merge-Flags loeschen
2190 RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
2195 void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
2197 ScDocumentPool* pDocPool = pDocument->GetPool();
2198 for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
2199 pDocPool->Remove(*pData[i].pPattern);
2201 memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) );
2202 nCount -= nEndIndex-nStartIndex+1;
2206 void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
2208 RemoveAreaMerge( nStartRow, nEndRow ); // von zusammengefassten auch die Flags loeschen
2210 if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) )
2211 SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
2212 else
2213 DeleteAreaSafe( nStartRow, nEndRow ); // Merge-Flags stehenlassen
2217 void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
2219 const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
2220 const ScPatternAttr* pOldPattern;
2222 SCSIZE nIndex;
2223 SCROW nRow;
2224 SCROW nThisRow;
2226 Search( nStartRow, nIndex );
2227 nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
2228 if (nThisRow < nStartRow) nThisRow = nStartRow;
2230 while ( nThisRow <= nEndRow )
2232 pOldPattern = pData[nIndex].pPattern;
2234 if ( pOldPattern->GetItemSet().Count() ) // harte Attribute ?
2236 nRow = pData[nIndex].nRow;
2237 SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
2239 ScPatternAttr aNewPattern(*pOldPattern);
2240 SfxItemSet& rSet = aNewPattern.GetItemSet();
2241 for (USHORT nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
2242 if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
2243 rSet.ClearItem(nId);
2245 if ( aNewPattern == *pDefPattern )
2246 SetPatternArea( nThisRow, nAttrRow, pDefPattern, FALSE );
2247 else
2248 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
2250 Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
2253 ++nIndex;
2254 nThisRow = pData[nIndex-1].nRow+1;
2258 // Verschieben innerhalb eines Dokuments
2260 void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
2262 SCROW nStart = nStartRow;
2263 for (SCSIZE i = 0; i < nCount; i++)
2265 if ((pData[i].nRow >= nStartRow) && ((i==0) ? TRUE : pData[i-1].nRow < nEndRow))
2267 // Kopieren (bPutToPool=TRUE)
2268 rAttrArray.SetPatternArea( nStart, Min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
2269 pData[i].pPattern, TRUE );
2271 nStart = Max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) );
2273 DeleteArea(nStartRow, nEndRow);
2277 // Kopieren zwischen Dokumenten (Clipboard)
2279 void ScAttrArray::CopyArea( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray,
2280 INT16 nStripFlags )
2282 nStartRow -= nDy; // Source
2283 nEndRow -= nDy;
2285 SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
2286 SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
2288 ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2289 ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2290 BOOL bSamePool = (pSourceDocPool==pDestDocPool);
2292 for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2294 if (pData[i].nRow >= nStartRow)
2296 const ScPatternAttr* pOldPattern = pData[i].pPattern;
2297 const ScPatternAttr* pNewPattern;
2299 if (IsDefaultItem( pOldPattern ))
2301 // am Default muss nichts veraendert werden
2303 pNewPattern = (const ScPatternAttr*)
2304 &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
2306 else if ( nStripFlags )
2308 ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern );
2309 INT16 nNewFlags = 0;
2310 if ( nStripFlags != SC_MF_ALL )
2311 nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)).
2312 GetValue() & ~nStripFlags;
2314 if ( nNewFlags )
2315 pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
2316 else
2317 pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
2319 if (bSamePool)
2320 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern);
2321 else
2322 pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
2323 delete pTmpPattern;
2325 else
2327 if (bSamePool)
2328 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2329 else
2330 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2333 rAttrArray.SetPatternArea(nDestStart,
2334 Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern);
2337 // when pasting from clipboard and skipping filtered rows, the adjusted end position
2338 // can be negative
2339 nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2343 // Flags stehenlassen
2344 //! mit CopyArea zusammenfassen !!!
2346 void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
2348 nStartRow -= nDy; // Source
2349 nEndRow -= nDy;
2351 SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
2352 SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
2354 if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) )
2356 CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
2357 return;
2360 ScDocumentPool* pSourceDocPool = pDocument->GetPool();
2361 ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
2362 BOOL bSamePool = (pSourceDocPool==pDestDocPool);
2364 for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
2366 if (pData[i].nRow >= nStartRow)
2368 const ScPatternAttr* pOldPattern = pData[i].pPattern;
2369 const ScPatternAttr* pNewPattern;
2371 if (bSamePool)
2372 pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
2373 else
2374 pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
2376 rAttrArray.SetPatternAreaSafe(nDestStart,
2377 Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, FALSE);
2380 // when pasting from clipboard and skipping filtered rows, the adjusted end position
2381 // can be negative
2382 nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
2387 SCsROW ScAttrArray::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
2388 BOOL bUp, ScMarkArray* pMarkArray )
2390 BOOL bFound = FALSE;
2392 if (pMarkArray)
2394 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2395 if (!VALIDROW(nRow))
2396 return nRow;
2399 SCSIZE nIndex;
2400 Search(nRow, nIndex);
2401 const ScPatternAttr* pPattern = pData[nIndex].pPattern;
2403 while (nIndex < nCount && !bFound)
2405 if (pPattern->GetStyleSheet() == pSearchStyle)
2407 if (pMarkArray)
2409 nRow = pMarkArray->GetNextMarked( nRow, bUp );
2410 SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
2411 if (nRow >= nStart && nRow <= pData[nIndex].nRow)
2412 bFound = TRUE;
2414 else
2415 bFound = TRUE;
2418 if (!bFound)
2420 if (bUp)
2422 if (nIndex==0)
2424 nIndex = nCount;
2425 nRow = -1;
2427 else
2429 --nIndex;
2430 nRow = pData[nIndex].nRow;
2431 pPattern = pData[nIndex].pPattern;
2434 else
2436 nRow = pData[nIndex].nRow+1;
2437 ++nIndex;
2438 if (nIndex<nCount)
2439 pPattern = pData[nIndex].pPattern;
2444 DBG_ASSERT( bFound || !ValidRow(nRow), "interner Fehler in ScAttrArray::SearchStyle" );
2446 return nRow;
2450 BOOL ScAttrArray::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow,
2451 const ScStyleSheet* pSearchStyle, BOOL bUp, ScMarkArray* pMarkArray )
2453 SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
2454 if (VALIDROW(nStartRow))
2456 SCSIZE nIndex;
2457 Search(nStartRow,nIndex);
2459 rRow = nStartRow;
2460 if (bUp)
2462 if (nIndex>0)
2463 rEndRow = pData[nIndex-1].nRow + 1;
2464 else
2465 rEndRow = 0;
2466 if (pMarkArray)
2468 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, TRUE );
2469 if (nMarkEnd>rEndRow)
2470 rEndRow = nMarkEnd;
2473 else
2475 rEndRow = pData[nIndex].nRow;
2476 if (pMarkArray)
2478 SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, FALSE );
2479 if (nMarkEnd<rEndRow)
2480 rEndRow = nMarkEnd;
2484 return TRUE;
2486 else
2487 return FALSE;
2490 //------------------------------------------------------------------------
2492 // Laden / Speichern
2496 #if 0
2497 void ScAttrArray::Save( SvStream& /* rStream */ ) const
2499 #if SC_ROWLIMIT_STREAM_ACCESS
2500 #error address types changed!
2501 ScWriteHeader aHdr( rStream, 8 );
2503 ScDocumentPool* pDocPool = pDocument->GetPool();
2505 USHORT nSaveCount = nCount;
2506 SCROW nSaveMaxRow = pDocument->GetSrcMaxRow();
2507 if ( nSaveMaxRow != MAXROW )
2509 if ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow )
2511 pDocument->SetLostData(); // Warnung ausgeben
2513 --nSaveCount;
2514 while ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow );
2518 rStream << nSaveCount;
2520 const SfxPoolItem* pItem;
2521 for (SCSIZE i=0; i<nSaveCount; i++)
2523 rStream << Min( pData[i].nRow, nSaveMaxRow );
2525 const ScPatternAttr* pPattern = pData[i].pPattern;
2526 pDocPool->StoreSurrogate( rStream, pPattern );
2528 // FALSE, weil ATTR_CONDITIONAL (noch) nicht in Vorlagen:
2529 if (pPattern->GetItemSet().GetItemState(ATTR_CONDITIONAL,FALSE,&pItem) == SFX_ITEM_SET)
2530 pDocument->SetConditionalUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
2532 if (pPattern->GetItemSet().GetItemState(ATTR_VALIDDATA,FALSE,&pItem) == SFX_ITEM_SET)
2533 pDocument->SetValidationUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
2535 #endif // SC_ROWLIMIT_STREAM_ACCESS
2539 void ScAttrArray::Load( SvStream& /* rStream */ )
2541 #if SC_ROWLIMIT_STREAM_ACCESS
2542 #error address types changed!
2543 ScDocumentPool* pDocPool = pDocument->GetPool();
2545 ScReadHeader aHdr( rStream );
2547 USHORT nNewCount;
2548 rStream >> nNewCount;
2549 if ( nNewCount > MAXROW+1 ) // wuerde das Array zu gross?
2551 pDocument->SetLostData();
2552 rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
2553 return;
2556 Reset( pDocument->GetDefPattern(), FALSE ); // loeschen
2557 pData = new ScAttrEntry[nNewCount]; // neu anlegen
2558 for (SCSIZE i=0; i<nNewCount; i++)
2560 rStream >> pData[i].nRow;
2562 USHORT nWhich = ATTR_PATTERN;
2563 const ScPatternAttr* pNewPattern = (const ScPatternAttr*)
2564 pDocPool->LoadSurrogate( rStream, nWhich, ATTR_PATTERN );
2565 if (!pNewPattern)
2567 // da is was schiefgelaufen
2568 DBG_ERROR("ScAttrArray::Load: Surrogat nicht im Pool");
2569 pNewPattern = pDocument->GetDefPattern();
2571 ScDocumentPool::CheckRef( *pNewPattern );
2572 pData[i].pPattern = pNewPattern;
2574 // LoadSurrogate erhoeht auch die Ref
2576 nCount = nLimit = nNewCount;
2578 if ( nCount > 1 && pData[nCount-2].nRow >= MAXROW ) // faengt ein Attribut hinter MAXROW an?
2580 pDocument->SetLostData();
2581 rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
2582 return;
2585 if ( pDocument->GetSrcMaxRow() != MAXROW ) // Ende anpassen?
2587 // Ende immer auf MAXROW umsetzen (nur auf 32 Bit)
2589 DBG_ASSERT( pData[nCount-1].nRow == pDocument->GetSrcMaxRow(), "Attribut-Ende ?!?" );
2590 pData[nCount-1].nRow = MAXROW;
2592 #endif // SC_ROWLIMIT_STREAM_ACCESS
2594 #endif
2597 //UNUSED2008-05 void ScAttrArray::ConvertFontsAfterLoad()
2598 //UNUSED2008-05 {
2599 //UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter;
2600 //UNUSED2008-05 const ULONG nFlags = FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
2601 //UNUSED2008-05 SCSIZE nIndex = 0;
2602 //UNUSED2008-05 SCROW nThisRow = 0;
2603 //UNUSED2008-05
2604 //UNUSED2008-05 while ( nThisRow <= MAXROW )
2605 //UNUSED2008-05 {
2606 //UNUSED2008-05 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
2607 //UNUSED2008-05 const SfxPoolItem* pItem;
2608 //UNUSED2008-05 if( pOldPattern->GetItemSet().GetItemState( ATTR_FONT, FALSE, &pItem ) == SFX_ITEM_SET )
2609 //UNUSED2008-05 {
2610 //UNUSED2008-05 const SvxFontItem* pFontItem = (const SvxFontItem*) pItem;
2611 //UNUSED2008-05 const String& rOldName = pFontItem->GetFamilyName();
2612 //UNUSED2008-05 xFontConverter = CreateFontToSubsFontConverter( rOldName, nFlags );
2613 //UNUSED2008-05 if ( xFontConverter )
2614 //UNUSED2008-05 {
2615 //UNUSED2008-05 String aNewName( GetFontToSubsFontName( xFontConverter ) );
2616 //UNUSED2008-05 if ( aNewName != rOldName )
2617 //UNUSED2008-05 {
2618 //UNUSED2008-05 SCROW nAttrRow = pData[nIndex].nRow;
2619 //UNUSED2008-05 SvxFontItem aNewItem( pFontItem->GetFamily(), aNewName,
2620 //UNUSED2008-05 pFontItem->GetStyleName(), pFontItem->GetPitch(),
2621 //UNUSED2008-05 RTL_TEXTENCODING_DONTKNOW, ATTR_FONT );
2622 //UNUSED2008-05 ScPatternAttr aNewPattern( *pOldPattern );
2623 //UNUSED2008-05 aNewPattern.GetItemSet().Put( aNewItem );
2624 //UNUSED2008-05 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
2625 //UNUSED2008-05 Search( nThisRow, nIndex ); //! data changed
2626 //UNUSED2008-05 }
2627 //UNUSED2008-05 }
2628 //UNUSED2008-05 }
2629 //UNUSED2008-05 ++nIndex;
2630 //UNUSED2008-05 nThisRow = pData[nIndex-1].nRow+1;
2631 //UNUSED2008-05 }
2632 //UNUSED2008-05 }