summaryrefslogtreecommitdiff
path: root/sc/source/core/data/attarray.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/data/attarray.cxx')
-rw-r--r--sc/source/core/data/attarray.cxx2612
1 files changed, 2612 insertions, 0 deletions
diff --git a/sc/source/core/data/attarray.cxx b/sc/source/core/data/attarray.cxx
new file mode 100644
index 000000000000..67be752fd8c8
--- /dev/null
+++ b/sc/source/core/data/attarray.cxx
@@ -0,0 +1,2612 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+
+
+
+//------------------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/bolnitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/shaditem.hxx>
+#include <svl/poolcach.hxx>
+#include <editeng/fontitem.hxx>
+#include <unotools/fontcvt.hxx>
+
+#include "attarray.hxx"
+#include "global.hxx"
+#include "document.hxx"
+#include "docpool.hxx"
+#include "patattr.hxx"
+#include "stlsheet.hxx"
+#include "stlpool.hxx"
+#include "markarr.hxx"
+#include "rechead.hxx"
+#include "globstr.hrc"
+
+
+#undef DBG_INVALIDATE
+#define DBGOUTPUT(s) \
+ DBG_ERROR( String("Invalidate ") + String(s) + String(": ") \
+ + String(nCol) + String('/') + String(aAdrStart.Row()) + String('/') + String(nTab) \
+ + String(" bis ") \
+ + String(nCol) + String('/') + String(aAdrEnd.Row()) + String('/') + String(nTab) \
+ );
+
+// STATIC DATA -----------------------------------------------------------
+
+
+//------------------------------------------------------------------------
+
+ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc ) :
+ nCol( nNewCol ),
+ nTab( nNewTab ),
+ pDocument( pDoc )
+{
+ nCount = nLimit = 1;
+ pData = new ScAttrEntry[1];
+ if (pData)
+ {
+ pData[0].nRow = MAXROW;
+ pData[0].pPattern = pDocument->GetDefPattern(); // ohne Put !!!
+ }
+}
+
+//------------------------------------------------------------------------
+
+ScAttrArray::~ScAttrArray()
+{
+#ifdef DBG_UTIL
+ TestData();
+#endif
+
+ if (pData)
+ {
+ ScDocumentPool* pDocPool = pDocument->GetPool();
+ for (SCSIZE i=0; i<nCount; i++)
+ pDocPool->Remove(*pData[i].pPattern);
+
+ delete[] pData;
+ }
+}
+
+//------------------------------------------------------------------------
+#ifdef DBG_UTIL
+void ScAttrArray::TestData() const
+{
+
+ USHORT nErr = 0;
+ if (pData)
+ {
+ SCSIZE nPos;
+ for (nPos=0; nPos<nCount; nPos++)
+ {
+ if (nPos > 0)
+ if (pData[nPos].pPattern == pData[nPos-1].pPattern || pData[nPos].nRow <= pData[nPos-1].nRow)
+ ++nErr;
+ if (pData[nPos].pPattern->Which() != ATTR_PATTERN)
+ ++nErr;
+ }
+ if ( nPos && pData[nPos-1].nRow != MAXROW )
+ ++nErr;
+ }
+ if (nErr)
+ {
+ ByteString aMsg = ByteString::CreateFromInt32(nErr);
+ aMsg += " errors in attribute array, column ";
+ aMsg += ByteString::CreateFromInt32(nCol);
+ DBG_ERROR( aMsg.GetBuffer() );
+ }
+}
+#endif
+
+//------------------------------------------------------------------------
+
+void ScAttrArray::Reset( const ScPatternAttr* pPattern, BOOL bAlloc )
+{
+ if (pData)
+ {
+ ScDocumentPool* pDocPool = pDocument->GetPool();
+ const ScPatternAttr* pOldPattern;
+ ScAddress aAdrStart( nCol, 0, nTab );
+ ScAddress aAdrEnd ( nCol, 0, nTab );
+
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
+ pOldPattern = pData[i].pPattern;
+ BOOL bNumFormatChanged;
+ if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+ pPattern->GetItemSet(), pOldPattern->GetItemSet() ) )
+ {
+ aAdrStart.SetRow( i ? pData[i-1].nRow+1 : 0 );
+ aAdrEnd .SetRow( pData[i].nRow );
+ pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+#ifdef DBG_INVALIDATE
+ DBGOUTPUT("Reset");
+#endif
+ }
+ // bedingtes Format gesetzt oder geloescht?
+ if ( &pPattern->GetItem(ATTR_CONDITIONAL) != &pOldPattern->GetItem(ATTR_CONDITIONAL) )
+ {
+ pDocument->ConditionalChanged( ((const SfxUInt32Item&)
+ pOldPattern->GetItem(ATTR_CONDITIONAL)).GetValue() );
+ pDocument->ConditionalChanged( ((const SfxUInt32Item&)
+ pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() );
+ }
+ pDocPool->Remove(*pOldPattern);
+ }
+ delete[] pData;
+
+ if (pDocument->IsStreamValid(nTab))
+ pDocument->SetStreamValid(nTab, FALSE);
+
+ if (bAlloc)
+ {
+ nCount = nLimit = 1;
+ pData = new ScAttrEntry[1];
+ if (pData)
+ {
+ ScPatternAttr* pNewPattern = (ScPatternAttr*) &pDocPool->Put(*pPattern);
+ pData[0].nRow = MAXROW;
+ pData[0].pPattern = pNewPattern;
+ }
+ }
+ else
+ {
+ nCount = nLimit = 0;
+ pData = NULL; // muss sofort wieder belegt werden !
+ }
+ }
+}
+
+
+BOOL ScAttrArray::Concat(SCSIZE nPos)
+{
+ BOOL bRet = FALSE;
+ if (pData && (nPos < nCount))
+ {
+ if (nPos > 0)
+ {
+ if (pData[nPos - 1].pPattern == pData[nPos].pPattern)
+ {
+ pData[nPos - 1].nRow = pData[nPos].nRow;
+ pDocument->GetPool()->Remove(*pData[nPos].pPattern);
+ memmove(&pData[nPos], &pData[nPos + 1], (nCount - nPos - 1) * sizeof(ScAttrEntry));
+ pData[nCount - 1].pPattern = NULL;
+ pData[nCount - 1].nRow = 0;
+ nCount--;
+ nPos--;
+ bRet = TRUE;
+ }
+ }
+ if (nPos + 1 < nCount)
+ {
+ if (pData[nPos + 1].pPattern == pData[nPos].pPattern)
+ {
+ pData[nPos].nRow = pData[nPos + 1].nRow;
+ pDocument->GetPool()->Remove(*pData[nPos].pPattern);
+ memmove(&pData[nPos + 1], &pData[nPos + 2], (nCount - nPos - 2) * sizeof(ScAttrEntry));
+ pData[nCount - 1].pPattern = NULL;
+ pData[nCount - 1].nRow = 0;
+ nCount--;
+ bRet = TRUE;
+ }
+ }
+ }
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScAttrArray::Search( SCROW nRow, SCSIZE& nIndex ) const
+{
+ long nLo = 0;
+ long nHi = static_cast<long>(nCount) - 1;
+ long nStartRow = 0;
+ long nEndRow = 0;
+ long i = 0;
+ BOOL bFound = (nCount == 1);
+ if (pData)
+ {
+ while ( !bFound && nLo <= nHi )
+ {
+ i = (nLo + nHi) / 2;
+ if (i > 0)
+ nStartRow = (long) pData[i - 1].nRow;
+ else
+ nStartRow = -1;
+ nEndRow = (long) pData[i].nRow;
+ if (nEndRow < (long) nRow)
+ nLo = ++i;
+ else
+ if (nStartRow >= (long) nRow)
+ nHi = --i;
+ else
+ bFound = TRUE;
+ }
+ }
+ else
+ bFound = FALSE;
+
+ if (bFound)
+ nIndex=(SCSIZE)i;
+ else
+ nIndex=0;
+ return bFound;
+}
+
+
+const ScPatternAttr* ScAttrArray::GetPattern( SCROW nRow ) const
+{
+ SCSIZE i;
+ if (Search( nRow, i ))
+ return pData[i].pPattern;
+ else
+ return NULL;
+}
+
+
+const ScPatternAttr* ScAttrArray::GetPatternRange( SCROW& rStartRow,
+ SCROW& rEndRow, SCROW nRow ) const
+{
+ SCSIZE nIndex;
+ if ( Search( nRow, nIndex ) )
+ {
+ if ( nIndex > 0 )
+ rStartRow = pData[nIndex-1].nRow + 1;
+ else
+ rStartRow = 0;
+ rEndRow = pData[nIndex].nRow;
+ return pData[nIndex].pPattern;
+ }
+ return NULL;
+}
+
+//------------------------------------------------------------------------
+
+void ScAttrArray::SetPattern( SCROW nRow, const ScPatternAttr* pPattern, BOOL bPutToPool )
+{
+ SetPatternArea( nRow, nRow, pPattern, bPutToPool );
+}
+
+
+void ScAttrArray::SetPatternArea(SCROW nStartRow, SCROW nEndRow, const ScPatternAttr *pPattern, BOOL bPutToPool )
+{
+ if (ValidRow(nStartRow) && ValidRow(nEndRow))
+ {
+ if (bPutToPool)
+ pPattern = (const ScPatternAttr*) &pDocument->GetPool()->Put(*pPattern);
+
+ if ((nStartRow == 0) && (nEndRow == MAXROW))
+ Reset(pPattern);
+ else
+ {
+ SCSIZE nNeeded = nCount + 2;
+ if ( nLimit < nNeeded )
+ {
+ nLimit += SC_ATTRARRAY_DELTA;
+ if ( nLimit < nNeeded )
+ nLimit = nNeeded;
+ ScAttrEntry* pNewData = new ScAttrEntry[nLimit];
+ memcpy( pNewData, pData, nCount*sizeof(ScAttrEntry) );
+ delete[] pData;
+ pData = pNewData;
+ }
+
+ ScAddress aAdrStart( nCol, 0, nTab );
+ ScAddress aAdrEnd ( nCol, 0, nTab );
+
+ SCSIZE ni = 0; // number of entries in beginning
+ SCSIZE nx = 0; // track position
+ SCROW ns = 0; // start row of track position
+ if ( nStartRow > 0 )
+ {
+ // skip beginning
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ ni = nIndex;
+
+ if ( ni > 0 )
+ {
+ nx = ni;
+ ns = pData[ni-1].nRow+1;
+ }
+ }
+
+ // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
+ // oder bedingte Formate neu gesetzt oder geloescht werden
+ while ( ns <= nEndRow )
+ {
+ const SfxItemSet& rNewSet = pPattern->GetItemSet();
+ const SfxItemSet& rOldSet = pData[nx].pPattern->GetItemSet();
+
+ BOOL bNumFormatChanged;
+ if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+ rNewSet, rOldSet ) )
+ {
+ aAdrStart.SetRow( Max(nStartRow,ns) );
+ aAdrEnd .SetRow( Min(nEndRow,pData[nx].nRow) );
+ pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+#ifdef DBG_INVALIDATE
+ DBGOUTPUT("SetPatternArea");
+#endif
+ }
+ if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
+ {
+ pDocument->ConditionalChanged( ((const SfxUInt32Item&)
+ rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
+ pDocument->ConditionalChanged( ((const SfxUInt32Item&)
+ rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
+ }
+ ns = pData[nx].nRow + 1;
+ nx++;
+ }
+
+ // continue modifying data array
+
+ SCSIZE nInsert; // insert position (MAXROWCOUNT := no insert)
+ BOOL bCombined = FALSE;
+ BOOL bSplit = FALSE;
+ if ( nStartRow > 0 )
+ {
+ nInsert = MAXROWCOUNT;
+ if ( pData[ni].pPattern != pPattern )
+ {
+ if ( ni == 0 || (pData[ni-1].nRow < nStartRow - 1) )
+ { // may be a split or a simple insert or just a shrink,
+ // row adjustment is done further down
+ if ( pData[ni].nRow > nEndRow )
+ bSplit = TRUE;
+ ni++;
+ nInsert = ni;
+ }
+ else if ( ni > 0 && pData[ni-1].nRow == nStartRow - 1 )
+ nInsert = ni;
+ }
+ if ( ni > 0 && pData[ni-1].pPattern == pPattern )
+ { // combine
+ pData[ni-1].nRow = nEndRow;
+ nInsert = MAXROWCOUNT;
+ bCombined = TRUE;
+ }
+ }
+ else
+ nInsert = 0;
+
+ SCSIZE nj = ni; // stop position of range to replace
+ while ( nj < nCount && pData[nj].nRow <= nEndRow )
+ nj++;
+ if ( !bSplit )
+ {
+ if ( nj < nCount && pData[nj].pPattern == pPattern )
+ { // combine
+ if ( ni > 0 )
+ {
+ if ( pData[ni-1].pPattern == pPattern )
+ { // adjacent entries
+ pData[ni-1].nRow = pData[nj].nRow;
+ nj++;
+ }
+ else if ( ni == nInsert )
+ pData[ni-1].nRow = nStartRow - 1; // shrink
+ }
+ nInsert = MAXROWCOUNT;
+ bCombined = TRUE;
+ }
+ else if ( ni > 0 && ni == nInsert )
+ pData[ni-1].nRow = nStartRow - 1; // shrink
+ }
+ ScDocumentPool* pDocPool = pDocument->GetPool();
+ if ( bSplit )
+ { // duplicate splitted entry in pool
+ pDocPool->Put( *pData[ni-1].pPattern );
+ }
+ if ( ni < nj )
+ { // remove middle entries
+ for ( SCSIZE nk=ni; nk<nj; nk++)
+ { // remove entries from pool
+ pDocPool->Remove( *pData[nk].pPattern );
+ }
+ if ( !bCombined )
+ { // replace one entry
+ pData[ni].nRow = nEndRow;
+ pData[ni].pPattern = pPattern;
+ ni++;
+ nInsert = MAXROWCOUNT;
+ }
+ if ( ni < nj )
+ { // remove entries
+ memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScAttrEntry) );
+ nCount -= nj - ni;
+ }
+ }
+
+ if ( nInsert < sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
+ { // insert or append new entry
+ if ( nInsert <= nCount )
+ {
+ if ( !bSplit )
+ memmove( pData + nInsert + 1, pData + nInsert,
+ (nCount - nInsert) * sizeof(ScAttrEntry) );
+ else
+ {
+ memmove( pData + nInsert + 2, pData + nInsert,
+ (nCount - nInsert) * sizeof(ScAttrEntry) );
+ pData[nInsert+1] = pData[nInsert-1];
+ nCount++;
+ }
+ }
+ if ( nInsert )
+ pData[nInsert-1].nRow = nStartRow - 1;
+ pData[nInsert].nRow = nEndRow;
+ pData[nInsert].pPattern = pPattern;
+ nCount++;
+ }
+
+ if (pDocument->IsStreamValid(nTab))
+ pDocument->SetStreamValid(nTab, FALSE);
+ }
+ }
+// InfoBox(0, String(nCount) + String(" Eintraege") ).Execute();
+
+#ifdef DBG_UTIL
+ TestData();
+#endif
+}
+
+
+void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, ScStyleSheet* pStyle )
+{
+ if (ValidRow(nStartRow) && ValidRow(nEndRow))
+ {
+ SCSIZE nPos;
+ SCROW nStart=0;
+ if (!Search( nStartRow, nPos ))
+ {
+ DBG_ERROR("Search-Fehler");
+ return;
+ }
+
+ ScAddress aAdrStart( nCol, 0, nTab );
+ ScAddress aAdrEnd ( nCol, 0, nTab );
+
+ do
+ {
+ const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
+ ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
+ pNewPattern->SetStyleSheet(pStyle);
+ SCROW nY1 = nStart;
+ SCROW nY2 = pData[nPos].nRow;
+ nStart = pData[nPos].nRow + 1;
+
+ if ( *pNewPattern == *pOldPattern )
+ {
+ // keep the original pattern (might be default)
+ // pNewPattern is deleted below
+ nPos++;
+ }
+ else if ( nY1 < nStartRow || nY2 > nEndRow )
+ {
+ if (nY1 < nStartRow) nY1=nStartRow;
+ if (nY2 > nEndRow) nY2=nEndRow;
+ SetPatternArea( nY1, nY2, pNewPattern, TRUE );
+ Search( nStart, nPos );
+ }
+ else
+ {
+ // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
+ // bedingte Formate in Vorlagen gibt es (noch) nicht
+
+ const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
+ const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
+
+ BOOL bNumFormatChanged;
+ if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+ rNewSet, rOldSet ) )
+ {
+ aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
+ aAdrEnd .SetRow( pData[nPos].nRow );
+ pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+#ifdef DBG_INVALIDATE
+ DBGOUTPUT("ApplyStyleArea");
+#endif
+ }
+
+ pDocument->GetPool()->Remove(*pData[nPos].pPattern);
+ pData[nPos].pPattern = (const ScPatternAttr*)
+ &pDocument->GetPool()->Put(*pNewPattern);
+ if (Concat(nPos))
+ Search(nStart, nPos);
+ else
+ nPos++;
+ }
+ delete pNewPattern;
+ }
+ while ((nStart <= nEndRow) && (nPos < nCount));
+
+ if (pDocument->IsStreamValid(nTab))
+ pDocument->SetStreamValid(nTab, FALSE);
+ }
+
+#ifdef DBG_UTIL
+ TestData();
+#endif
+}
+
+
+ // const wird weggecastet, weil es sonst
+ // zu ineffizient/kompliziert wird!
+#define SET_LINECOLOR(dest,c) \
+ if ((dest)) \
+ { \
+ ((SvxBorderLine*)(dest))->SetColor((c)); \
+ }
+
+#define SET_LINE(dest,src) \
+ if ((dest)) \
+ { \
+ SvxBorderLine* pCast = (SvxBorderLine*)(dest); \
+ pCast->SetOutWidth((src)->GetOutWidth()); \
+ pCast->SetInWidth ((src)->GetInWidth()); \
+ pCast->SetDistance((src)->GetDistance()); \
+ }
+
+void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
+ const SvxBorderLine* pLine, BOOL bColorOnly )
+{
+ if ( bColorOnly && !pLine )
+ return;
+
+ if (ValidRow(nStartRow) && ValidRow(nEndRow))
+ {
+ SCSIZE nPos;
+ SCROW nStart=0;
+ if (!Search( nStartRow, nPos ))
+ {
+ DBG_ERROR("Search-Fehler");
+ return;
+ }
+
+ do
+ {
+ const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
+ const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
+ const SfxPoolItem* pBoxItem = 0;
+ SfxItemState eState = rOldSet.GetItemState( ATTR_BORDER, TRUE, &pBoxItem );
+ const SfxPoolItem* pTLBRItem = 0;
+ SfxItemState eTLBRState = rOldSet.GetItemState( ATTR_BORDER_TLBR, TRUE, &pTLBRItem );
+ const SfxPoolItem* pBLTRItem = 0;
+ SfxItemState eBLTRState = rOldSet.GetItemState( ATTR_BORDER_BLTR, TRUE, &pBLTRItem );
+
+ if ( (SFX_ITEM_SET == eState) || (SFX_ITEM_SET == eTLBRState) || (SFX_ITEM_SET == eBLTRState) )
+ {
+ ScPatternAttr* pNewPattern = new ScPatternAttr(*pOldPattern);
+ SfxItemSet& rNewSet = pNewPattern->GetItemSet();
+ SCROW nY1 = nStart;
+ SCROW nY2 = pData[nPos].nRow;
+
+ SvxBoxItem* pNewBoxItem = pBoxItem ? (SvxBoxItem*)pBoxItem->Clone() : 0;
+ SvxLineItem* pNewTLBRItem = pTLBRItem ? (SvxLineItem*)pTLBRItem->Clone() : 0;
+ SvxLineItem* pNewBLTRItem = pBLTRItem ? (SvxLineItem*)pBLTRItem->Clone() : 0;
+
+ // Linienattribute holen und mit Parametern aktualisieren
+
+ if ( !pLine )
+ {
+ if( pNewBoxItem )
+ {
+ if ( pNewBoxItem->GetTop() ) pNewBoxItem->SetLine( NULL, BOX_LINE_TOP );
+ if ( pNewBoxItem->GetBottom() ) pNewBoxItem->SetLine( NULL, BOX_LINE_BOTTOM );
+ if ( pNewBoxItem->GetLeft() ) pNewBoxItem->SetLine( NULL, BOX_LINE_LEFT );
+ if ( pNewBoxItem->GetRight() ) pNewBoxItem->SetLine( NULL, BOX_LINE_RIGHT );
+ }
+ if( pNewTLBRItem && pNewTLBRItem->GetLine() )
+ pNewTLBRItem->SetLine( 0 );
+ if( pNewBLTRItem && pNewBLTRItem->GetLine() )
+ pNewBLTRItem->SetLine( 0 );
+ }
+ else
+ {
+ if ( bColorOnly )
+ {
+ Color aColor( pLine->GetColor() );
+ if( pNewBoxItem )
+ {
+ SET_LINECOLOR( pNewBoxItem->GetTop(), aColor );
+ SET_LINECOLOR( pNewBoxItem->GetBottom(), aColor );
+ SET_LINECOLOR( pNewBoxItem->GetLeft(), aColor );
+ SET_LINECOLOR( pNewBoxItem->GetRight(), aColor );
+ }
+ if( pNewTLBRItem )
+ SET_LINECOLOR( pNewTLBRItem->GetLine(), aColor );
+ if( pNewBLTRItem )
+ SET_LINECOLOR( pNewBLTRItem->GetLine(), aColor );
+ }
+ else
+ {
+ if( pNewBoxItem )
+ {
+ SET_LINE( pNewBoxItem->GetTop(), pLine );
+ SET_LINE( pNewBoxItem->GetBottom(), pLine );
+ SET_LINE( pNewBoxItem->GetLeft(), pLine );
+ SET_LINE( pNewBoxItem->GetRight(), pLine );
+ }
+ if( pNewTLBRItem )
+ SET_LINE( pNewTLBRItem->GetLine(), pLine );
+ if( pNewBLTRItem )
+ SET_LINE( pNewBLTRItem->GetLine(), pLine );
+ }
+ }
+ if( pNewBoxItem ) rNewSet.Put( *pNewBoxItem );
+ if( pNewTLBRItem ) rNewSet.Put( *pNewTLBRItem );
+ if( pNewBLTRItem ) rNewSet.Put( *pNewBLTRItem );
+
+ nStart = pData[nPos].nRow + 1;
+
+ if ( nY1 < nStartRow || nY2 > nEndRow )
+ {
+ if (nY1 < nStartRow) nY1=nStartRow;
+ if (nY2 > nEndRow) nY2=nEndRow;
+ SetPatternArea( nY1, nY2, pNewPattern, TRUE );
+ Search( nStart, nPos );
+ }
+ else
+ {
+ //! aus Pool loeschen?
+ pDocument->GetPool()->Remove(*pData[nPos].pPattern);
+ pData[nPos].pPattern = (const ScPatternAttr*)
+ &pDocument->GetPool()->Put(*pNewPattern);
+
+ if (Concat(nPos))
+ Search(nStart, nPos);
+ else
+ nPos++;
+ }
+ delete pNewBoxItem;
+ delete pNewTLBRItem;
+ delete pNewBLTRItem;
+ delete pNewPattern;
+ }
+ else
+ {
+ nStart = pData[nPos].nRow + 1;
+ nPos++;
+ }
+ }
+ while ((nStart <= nEndRow) && (nPos < nCount));
+ }
+}
+
+#undef SET_LINECOLOR
+#undef SET_LINE
+
+
+void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCache* pCache )
+{
+#ifdef DBG_UTIL
+ TestData();
+#endif
+
+ if (ValidRow(nStartRow) && ValidRow(nEndRow))
+ {
+ SCSIZE nPos;
+ SCROW nStart=0;
+ if (!Search( nStartRow, nPos ))
+ {
+ DBG_ERROR("Search-Fehler");
+ return;
+ }
+
+ ScAddress aAdrStart( nCol, 0, nTab );
+ ScAddress aAdrEnd ( nCol, 0, nTab );
+
+ do
+ {
+ const ScPatternAttr* pOldPattern = pData[nPos].pPattern;
+ const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pCache->ApplyTo( *pOldPattern, TRUE );
+ ScDocumentPool::CheckRef( *pOldPattern );
+ ScDocumentPool::CheckRef( *pNewPattern );
+ if (pNewPattern != pOldPattern)
+ {
+ SCROW nY1 = nStart;
+ SCROW nY2 = pData[nPos].nRow;
+ nStart = pData[nPos].nRow + 1;
+
+ if ( nY1 < nStartRow || nY2 > nEndRow )
+ {
+ if (nY1 < nStartRow) nY1=nStartRow;
+ if (nY2 > nEndRow) nY2=nEndRow;
+ SetPatternArea( nY1, nY2, pNewPattern );
+ Search( nStart, nPos );
+ }
+ else
+ {
+ // ueberpruefen, ob Attributierung die Textbreite der Zelle aendert
+
+ const SfxItemSet& rNewSet = pNewPattern->GetItemSet();
+ const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
+
+ BOOL bNumFormatChanged;
+ if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+ rNewSet, rOldSet ) )
+ {
+ aAdrStart.SetRow( nPos ? pData[nPos-1].nRow+1 : 0 );
+ aAdrEnd .SetRow( pData[nPos].nRow );
+ pDocument->InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
+#ifdef DBG_INVALIDATE
+ DBGOUTPUT("ApplyCacheArea");
+#endif
+ }
+
+ // bedingte Formate neu gesetzt oder geloescht ?
+
+ if ( &rNewSet.Get(ATTR_CONDITIONAL) != &rOldSet.Get(ATTR_CONDITIONAL) )
+ {
+ pDocument->ConditionalChanged( ((const SfxUInt32Item&)
+ rOldSet.Get(ATTR_CONDITIONAL)).GetValue() );
+ pDocument->ConditionalChanged( ((const SfxUInt32Item&)
+ rNewSet.Get(ATTR_CONDITIONAL)).GetValue() );
+ }
+
+ pDocument->GetPool()->Remove(*pData[nPos].pPattern);
+ pData[nPos].pPattern = pNewPattern;
+ if (Concat(nPos))
+ Search(nStart, nPos);
+ else
+ ++nPos;
+ }
+ }
+ else
+ {
+//!!!!!!!!!!!!!!!!!! mit diesem Remove gibt es Abstuerze (Calc1 Import)
+//! pDocument->GetPool()->Remove(*pNewPattern);
+ nStart = pData[nPos].nRow + 1;
+ ++nPos;
+ }
+ }
+ while (nStart <= nEndRow);
+
+ if (pDocument->IsStreamValid(nTab))
+ pDocument->SetStreamValid(nTab, FALSE);
+ }
+
+#ifdef DBG_UTIL
+ TestData();
+#endif
+}
+
+
+void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
+{
+ const SfxPoolItem* pNewItem;
+ const SfxPoolItem* pOldItem;
+ for (USHORT nId=ATTR_PATTERN_START; nId<=ATTR_PATTERN_END; nId++)
+ {
+ // pMergeSet hat keinen Parent
+ SfxItemState eOldState = rMergeSet.GetItemState( nId, FALSE, &pOldItem );
+
+ if ( eOldState == SFX_ITEM_DEFAULT ) // Default
+ {
+ SfxItemState eNewState = rSource.GetItemState( nId, TRUE, &pNewItem );
+ if ( eNewState == SFX_ITEM_SET )
+ {
+ if ( *pNewItem != rMergeSet.GetPool()->GetDefaultItem(nId) )
+ rMergeSet.InvalidateItem( nId );
+ }
+ }
+ else if ( eOldState == SFX_ITEM_SET ) // Item gesetzt
+ {
+ SfxItemState eNewState = rSource.GetItemState( nId, TRUE, &pNewItem );
+ if ( eNewState == SFX_ITEM_SET )
+ {
+ if ( pNewItem != pOldItem ) // beide gepuhlt
+ rMergeSet.InvalidateItem( nId );
+ }
+ else // Default
+ {
+ if ( *pOldItem != rSource.GetPool()->GetDefaultItem(nId) )
+ rMergeSet.InvalidateItem( nId );
+ }
+ }
+ // Dontcare bleibt Dontcare
+ }
+}
+
+
+void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
+ ScMergePatternState& rState, BOOL bDeep ) const
+{
+ if (ValidRow(nStartRow) && ValidRow(nEndRow))
+ {
+ SCSIZE nPos;
+ SCROW nStart=0;
+ if (!Search( nStartRow, nPos ))
+ {
+ DBG_ERROR("Search-Fehler");
+ return;
+ }
+
+ do
+ {
+ // gleiche Patterns muessen nicht mehrfach angesehen werden
+
+ const ScPatternAttr* pPattern = pData[nPos].pPattern;
+ if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
+ {
+ const SfxItemSet& rThisSet = pPattern->GetItemSet();
+ if (rState.pItemSet)
+ {
+ // (*ppSet)->MergeValues( rThisSet, FALSE );
+ // geht nicht, weil die Vorlagen nicht beruecksichtigt werden
+
+ if (bDeep)
+ lcl_MergeDeep( *rState.pItemSet, rThisSet );
+ else
+ rState.pItemSet->MergeValues( rThisSet, FALSE );
+ }
+ else
+ {
+ // erstes Pattern - in Set ohne Parent kopieren
+ rState.pItemSet = new SfxItemSet( *rThisSet.GetPool(), rThisSet.GetRanges() );
+ rState.pItemSet->Set( rThisSet, bDeep );
+ }
+
+ rState.pOld2 = rState.pOld1;
+ rState.pOld1 = pPattern;
+ }
+
+ nStart = pData[nPos].nRow + 1;
+ ++nPos;
+ }
+ while (nStart <= nEndRow);
+ }
+}
+
+
+
+// Umrandung zusammenbauen
+
+BOOL lcl_TestAttr( const SvxBorderLine* pOldLine, const SvxBorderLine* pNewLine,
+ BYTE& rModified, const SvxBorderLine*& rpNew )
+{
+ if (rModified == SC_LINE_DONTCARE)
+ return FALSE; // weiter geht's nicht
+
+ if (rModified == SC_LINE_EMPTY)
+ {
+ rModified = SC_LINE_SET;
+ rpNew = pNewLine;
+ return TRUE; // zum ersten mal gesetzt
+ }
+
+ if (pOldLine == pNewLine)
+ {
+ rpNew = pOldLine;
+ return FALSE;
+ }
+
+ if (pOldLine && pNewLine)
+ if (*pOldLine == *pNewLine)
+ {
+ rpNew = pOldLine;
+ return FALSE;
+ }
+
+ rModified = SC_LINE_DONTCARE;
+ rpNew = NULL;
+ return TRUE; // andere Linie -> dontcare
+}
+
+
+void lcl_MergeToFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
+ ScLineFlags& rFlags, const ScPatternAttr* pPattern,
+ BOOL bLeft, SCCOL nDistRight, BOOL bTop, SCROW nDistBottom )
+{
+ // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst:
+ const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
+ if ( rMerge.GetColMerge() == nDistRight + 1 )
+ nDistRight = 0;
+ if ( rMerge.GetRowMerge() == nDistBottom + 1 )
+ nDistBottom = 0;
+
+ const SvxBoxItem* pCellFrame = (SvxBoxItem*) &pPattern->GetItemSet().Get( ATTR_BORDER );
+ const SvxBorderLine* pLeftAttr = pCellFrame->GetLeft();
+ const SvxBorderLine* pRightAttr = pCellFrame->GetRight();
+ const SvxBorderLine* pTopAttr = pCellFrame->GetTop();
+ const SvxBorderLine* pBottomAttr = pCellFrame->GetBottom();
+ const SvxBorderLine* pNew;
+
+ if (bTop)
+ {
+ if (lcl_TestAttr( pLineOuter->GetTop(), pTopAttr, rFlags.nTop, pNew ))
+ pLineOuter->SetLine( pNew, BOX_LINE_TOP );
+ }
+ else
+ {
+ if (lcl_TestAttr( pLineInner->GetHori(), pTopAttr, rFlags.nHori, pNew ))
+ pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
+ }
+
+ if (nDistBottom == 0)
+ {
+ if (lcl_TestAttr( pLineOuter->GetBottom(), pBottomAttr, rFlags.nBottom, pNew ))
+ pLineOuter->SetLine( pNew, BOX_LINE_BOTTOM );
+ }
+ else
+ {
+ if (lcl_TestAttr( pLineInner->GetHori(), pBottomAttr, rFlags.nHori, pNew ))
+ pLineInner->SetLine( pNew, BOXINFO_LINE_HORI );
+ }
+
+ if (bLeft)
+ {
+ if (lcl_TestAttr( pLineOuter->GetLeft(), pLeftAttr, rFlags.nLeft, pNew ))
+ pLineOuter->SetLine( pNew, BOX_LINE_LEFT );
+ }
+ else
+ {
+ if (lcl_TestAttr( pLineInner->GetVert(), pLeftAttr, rFlags.nVert, pNew ))
+ pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
+ }
+
+ if (nDistRight == 0)
+ {
+ if (lcl_TestAttr( pLineOuter->GetRight(), pRightAttr, rFlags.nRight, pNew ))
+ pLineOuter->SetLine( pNew, BOX_LINE_RIGHT );
+ }
+ else
+ {
+ if (lcl_TestAttr( pLineInner->GetVert(), pRightAttr, rFlags.nVert, pNew ))
+ pLineInner->SetLine( pNew, BOXINFO_LINE_VERT );
+ }
+}
+
+
+void ScAttrArray::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
+ ScLineFlags& rFlags,
+ SCROW nStartRow, SCROW nEndRow, BOOL bLeft, SCCOL nDistRight ) const
+{
+ const ScPatternAttr* pPattern;
+
+ if (nStartRow == nEndRow)
+ {
+ pPattern = GetPattern( nStartRow );
+ lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, TRUE, 0 );
+ }
+ else
+ {
+ pPattern = GetPattern( nStartRow );
+ lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, TRUE,
+ nEndRow-nStartRow );
+
+ SCSIZE nStartIndex;
+ SCSIZE nEndIndex;
+ Search( nStartRow+1, nStartIndex );
+ Search( nEndRow-1, nEndIndex );
+ for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
+ {
+ pPattern = (ScPatternAttr*) pData[i].pPattern;
+ lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, FALSE,
+ nEndRow - Min( pData[i].nRow, (SCROW)(nEndRow-1) ) );
+ // nDistBottom hier immer > 0
+ }
+
+ pPattern = GetPattern( nEndRow );
+ lcl_MergeToFrame( pLineOuter, pLineInner, rFlags, pPattern, bLeft, nDistRight, FALSE, 0 );
+ }
+}
+
+//
+// Rahmen anwenden
+//
+
+// ApplyFrame - auf einen Eintrag im Array
+
+
+BOOL ScAttrArray::ApplyFrame( const SvxBoxItem* pBoxItem,
+ const SvxBoxInfoItem* pBoxInfoItem,
+ SCROW nStartRow, SCROW nEndRow,
+ BOOL bLeft, SCCOL nDistRight, BOOL bTop, SCROW nDistBottom )
+{
+ DBG_ASSERT( pBoxItem && pBoxInfoItem, "Linienattribute fehlen!" );
+
+ const ScPatternAttr* pPattern = GetPattern( nStartRow );
+ const SvxBoxItem* pOldFrame = (const SvxBoxItem*)
+ &pPattern->GetItemSet().Get( ATTR_BORDER );
+
+ // rechten/unteren Rahmen setzen, wenn Zelle bis zum Ende zusammengefasst:
+ const ScMergeAttr& rMerge = (const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE);
+ if ( rMerge.GetColMerge() == nDistRight + 1 )
+ nDistRight = 0;
+ if ( rMerge.GetRowMerge() == nDistBottom + 1 )
+ nDistBottom = 0;
+
+ SvxBoxItem aNewFrame( *pOldFrame );
+
+ if ( bLeft ? pBoxInfoItem->IsValid(VALID_LEFT) : pBoxInfoItem->IsValid(VALID_VERT) )
+ aNewFrame.SetLine( bLeft ? pBoxItem->GetLeft() : pBoxInfoItem->GetVert(),
+ BOX_LINE_LEFT );
+ if ( (nDistRight==0) ? pBoxInfoItem->IsValid(VALID_RIGHT) : pBoxInfoItem->IsValid(VALID_VERT) )
+ aNewFrame.SetLine( (nDistRight==0) ? pBoxItem->GetRight() : pBoxInfoItem->GetVert(),
+ BOX_LINE_RIGHT );
+ if ( bTop ? pBoxInfoItem->IsValid(VALID_TOP) : pBoxInfoItem->IsValid(VALID_HORI) )
+ aNewFrame.SetLine( bTop ? pBoxItem->GetTop() : pBoxInfoItem->GetHori(),
+ BOX_LINE_TOP );
+ if ( (nDistBottom==0) ? pBoxInfoItem->IsValid(VALID_BOTTOM) : pBoxInfoItem->IsValid(VALID_HORI) )
+ aNewFrame.SetLine( (nDistBottom==0) ? pBoxItem->GetBottom() : pBoxInfoItem->GetHori(),
+ BOX_LINE_BOTTOM );
+
+ if (aNewFrame == *pOldFrame)
+ {
+ // nothing to do
+ return FALSE;
+ }
+ else
+ {
+ SfxItemPoolCache aCache( pDocument->GetPool(), &aNewFrame );
+ ApplyCacheArea( nStartRow, nEndRow, &aCache );
+
+/* ScPatternAttr* pNewPattern = (ScPatternAttr*) pPattern->Clone();
+ pNewPattern->GetItemSet().Put( aNewFrame );
+ SetPatternArea( nStartRow, nEndRow, pNewPattern, TRUE );
+*/
+ return TRUE;
+ }
+}
+
+
+void ScAttrArray::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
+ SCROW nStartRow, SCROW nEndRow, BOOL bLeft, SCCOL nDistRight )
+{
+ if (nStartRow == nEndRow)
+ ApplyFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight, TRUE, 0 );
+ else
+ {
+ ApplyFrame( pLineOuter, pLineInner, nStartRow, nStartRow, bLeft, nDistRight,
+ TRUE, nEndRow-nStartRow );
+
+ if ( nEndRow > nStartRow+1 ) // innerer Teil vorhanden?
+ {
+ SCSIZE nStartIndex;
+ SCSIZE nEndIndex;
+ Search( nStartRow+1, nStartIndex );
+ Search( nEndRow-1, nEndIndex );
+ SCROW nTmpStart = nStartRow+1;
+ SCROW nTmpEnd;
+ for (SCSIZE i=nStartIndex; i<=nEndIndex;)
+ {
+ nTmpEnd = Min( (SCROW)(nEndRow-1), (SCROW)(pData[i].nRow) );
+ BOOL bChanged = ApplyFrame( pLineOuter, pLineInner, nTmpStart, nTmpEnd,
+ bLeft, nDistRight, FALSE, nEndRow-nTmpEnd );
+ nTmpStart = nTmpEnd+1;
+ if (bChanged)
+ {
+ Search(nTmpStart, i);
+ Search(nEndRow-1, nEndIndex);
+ }
+ else
+ i++;
+ }
+ }
+
+ ApplyFrame( pLineOuter, pLineInner, nEndRow, nEndRow, bLeft, nDistRight, FALSE, 0 );
+ }
+}
+
+
+long lcl_LineSize( const SvxBorderLine& rLine )
+{
+ // nur eine Linie -> halbe Breite, min. 20
+ // doppelte Linie -> halber Abstand + eine Linie (je min. 20)
+
+ long nTotal = 0;
+ USHORT nWidth = Max( rLine.GetOutWidth(), rLine.GetInWidth() );
+ USHORT nDist = rLine.GetDistance();
+ if (nDist)
+ {
+ DBG_ASSERT( rLine.GetOutWidth() && rLine.GetInWidth(),
+ "Linie hat Abstand, aber nur eine Breite ???" );
+
+// nTotal += ( nDist > 40 ) ? ( nDist / 2 ) : 20;
+ nTotal += ( nDist > 20 ) ? nDist : 20;
+ nTotal += ( nWidth > 20 ) ? nWidth : 20;
+ }
+ else if (nWidth)
+// nTotal += ( nWidth > 40 ) ? ( nWidth / 2 ) : 20;
+ nTotal += ( nWidth > 20 ) ? nWidth : 20;
+
+ //! auch halbieren ???
+
+ return nTotal;
+}
+
+
+BOOL ScAttrArray::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
+ BOOL bLeft, BOOL bRight ) const
+{
+ SCSIZE nStartIndex;
+ SCSIZE nEndIndex;
+ Search( nRow1, nStartIndex );
+ Search( nRow2, nEndIndex );
+ BOOL bFound = FALSE;
+
+ const SvxBoxItem* pItem = 0;
+ const SvxBorderLine* pLine = 0;
+ long nCmp;
+
+ // oben
+
+ pItem = (const SvxBoxItem*) &pData[nStartIndex].pPattern->GetItem(ATTR_BORDER);
+ pLine = pItem->GetTop();
+ if (pLine)
+ {
+ nCmp = lcl_LineSize(*pLine);
+ if ( nCmp > rSizes.Top() )
+ rSizes.Top() = nCmp;
+ bFound = TRUE;
+ }
+
+ // unten
+
+ if ( nEndIndex != nStartIndex )
+ pItem = (const SvxBoxItem*) &pData[nEndIndex].pPattern->GetItem(ATTR_BORDER);
+ pLine = pItem->GetBottom();
+ if (pLine)
+ {
+ nCmp = lcl_LineSize(*pLine);
+ if ( nCmp > rSizes.Bottom() )
+ rSizes.Bottom() = nCmp;
+ bFound = TRUE;
+ }
+
+ if ( bLeft || bRight )
+ for ( SCSIZE i=nStartIndex; i<=nEndIndex; i++)
+ {
+ pItem = (const SvxBoxItem*) &pData[i].pPattern->GetItem(ATTR_BORDER);
+
+ // links
+
+ if (bLeft)
+ {
+ pLine = pItem->GetLeft();
+ if (pLine)
+ {
+ nCmp = lcl_LineSize(*pLine);
+ if ( nCmp > rSizes.Left() )
+ rSizes.Left() = nCmp;
+ bFound = TRUE;
+ }
+ }
+
+ // rechts
+
+ if (bRight)
+ {
+ pLine = pItem->GetRight();
+ if (pLine)
+ {
+ nCmp = lcl_LineSize(*pLine);
+ if ( nCmp > rSizes.Right() )
+ rSizes.Right() = nCmp;
+ bFound = TRUE;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+// Testen, ob Bereich bestimmtes Attribut enthaelt
+
+BOOL ScAttrArray::HasAttrib( SCROW nRow1, SCROW nRow2, USHORT nMask ) const
+{
+ SCSIZE nStartIndex;
+ SCSIZE nEndIndex;
+ Search( nRow1, nStartIndex );
+ Search( nRow2, nEndIndex );
+ BOOL bFound = FALSE;
+
+ for (SCSIZE i=nStartIndex; i<=nEndIndex && !bFound; i++)
+ {
+ const ScPatternAttr* pPattern = pData[i].pPattern;
+ if ( nMask & HASATTR_MERGED )
+ {
+ const ScMergeAttr* pMerge =
+ (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
+ if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
+ bFound = TRUE;
+ }
+ if ( nMask & ( HASATTR_OVERLAPPED | HASATTR_NOTOVERLAPPED | HASATTR_AUTOFILTER ) )
+ {
+ const ScMergeFlagAttr* pMergeFlag =
+ (const ScMergeFlagAttr*) &pPattern->GetItem( ATTR_MERGE_FLAG );
+ if ( (nMask & HASATTR_OVERLAPPED) && pMergeFlag->IsOverlapped() )
+ bFound = TRUE;
+ if ( (nMask & HASATTR_NOTOVERLAPPED) && !pMergeFlag->IsOverlapped() )
+ bFound = TRUE;
+ if ( (nMask & HASATTR_AUTOFILTER) && pMergeFlag->HasAutoFilter() )
+ bFound = TRUE;
+ }
+ if ( nMask & HASATTR_LINES )
+ {
+ const SvxBoxItem* pBox =
+ (const SvxBoxItem*) &pPattern->GetItem( ATTR_BORDER );
+ if ( pBox->GetLeft() || pBox->GetRight() || pBox->GetTop() || pBox->GetBottom() )
+ bFound = TRUE;
+ }
+ if ( nMask & HASATTR_SHADOW )
+ {
+ const SvxShadowItem* pShadow =
+ (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
+ if ( pShadow->GetLocation() != SVX_SHADOW_NONE )
+ bFound = TRUE;
+ }
+ if ( nMask & HASATTR_CONDITIONAL )
+ {
+ const SfxUInt32Item* pConditional =
+ (const SfxUInt32Item*) &pPattern->GetItem( ATTR_CONDITIONAL );
+ if ( pConditional->GetValue() != 0 )
+ bFound = TRUE;
+ }
+ if ( nMask & HASATTR_PROTECTED )
+ {
+ const ScProtectionAttr* pProtect =
+ (const ScProtectionAttr*) &pPattern->GetItem( ATTR_PROTECTION );
+ if ( pProtect->GetProtection() || pProtect->GetHideCell() )
+ bFound = TRUE;
+ }
+ if ( nMask & HASATTR_ROTATE )
+ {
+ const SfxInt32Item* pRotate =
+ (const SfxInt32Item*) &pPattern->GetItem( ATTR_ROTATE_VALUE );
+ // 90 or 270 degrees is former SvxOrientationItem - only look for other values
+ // (see ScPatternAttr::GetCellOrientation)
+ INT32 nAngle = pRotate->GetValue();
+ if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
+ bFound = TRUE;
+ }
+ if ( nMask & HASATTR_NEEDHEIGHT )
+ {
+ if (pPattern->GetCellOrientation() != SVX_ORIENTATION_STANDARD)
+ bFound = TRUE;
+ else if (((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK )).GetValue())
+ bFound = TRUE;
+ else if ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
+ GetItem( ATTR_HOR_JUSTIFY )).GetValue() == SVX_HOR_JUSTIFY_BLOCK)
+ bFound = TRUE;
+ else if (((const SfxUInt32Item&)pPattern->GetItem( ATTR_CONDITIONAL )).GetValue())
+ bFound = TRUE;
+ else if (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE )).GetValue())
+ bFound = TRUE;
+ }
+ if ( nMask & ( HASATTR_SHADOW_RIGHT | HASATTR_SHADOW_DOWN ) )
+ {
+ const SvxShadowItem* pShadow =
+ (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
+ SvxShadowLocation eLoc = pShadow->GetLocation();
+ if ( nMask & HASATTR_SHADOW_RIGHT )
+ if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
+ bFound = TRUE;
+ if ( nMask & HASATTR_SHADOW_DOWN )
+ if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
+ bFound = TRUE;
+ }
+ if ( nMask & HASATTR_RTL )
+ {
+ const SvxFrameDirectionItem& rDirection =
+ (const SvxFrameDirectionItem&) pPattern->GetItem( ATTR_WRITINGDIR );
+ if ( rDirection.GetValue() == FRMDIR_HORI_RIGHT_TOP )
+ bFound = TRUE;
+ }
+ if ( nMask & HASATTR_RIGHTORCENTER )
+ {
+ // called only if the sheet is LTR, so physical=logical alignment can be assumed
+ SvxCellHorJustify eHorJust = (SvxCellHorJustify)
+ ((const SvxHorJustifyItem&) pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
+ if ( eHorJust == SVX_HOR_JUSTIFY_RIGHT || eHorJust == SVX_HOR_JUSTIFY_CENTER )
+ bFound = TRUE;
+ }
+ }
+
+ return bFound;
+}
+
+// Bereich um evtl. enthaltene Zusammenfassungen erweitern
+// und evtl. MergeFlag anpassen (bRefresh)
+
+BOOL ScAttrArray::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
+ SCCOL& rPaintCol, SCROW& rPaintRow,
+ BOOL bRefresh, BOOL bAttrs )
+{
+ const ScPatternAttr* pPattern;
+ const ScMergeAttr* pItem;
+ SCSIZE nStartIndex;
+ SCSIZE nEndIndex;
+ Search( nStartRow, nStartIndex );
+ Search( nEndRow, nEndIndex );
+ BOOL bFound = FALSE;
+
+ for (SCSIZE i=nStartIndex; i<=nEndIndex; i++)
+ {
+ pPattern = pData[i].pPattern;
+ pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
+ SCsCOL nCountX = pItem->GetColMerge();
+ SCsROW nCountY = pItem->GetRowMerge();
+ if (nCountX>1 || nCountY>1)
+ {
+ SCROW nThisRow = (i>0) ? pData[i-1].nRow+1 : 0;
+ SCCOL nMergeEndCol = nThisCol + nCountX - 1;
+ SCROW nMergeEndRow = nThisRow + nCountY - 1;
+ if (nMergeEndCol > rPaintCol && nMergeEndCol <= MAXCOL)
+ rPaintCol = nMergeEndCol;
+ if (nMergeEndRow > rPaintRow && nMergeEndRow <= MAXROW)
+ rPaintRow = nMergeEndRow;
+ bFound = TRUE;
+
+ if (bAttrs)
+ {
+ const SvxShadowItem* pShadow =
+ (const SvxShadowItem*) &pPattern->GetItem( ATTR_SHADOW );
+ SvxShadowLocation eLoc = pShadow->GetLocation();
+ if ( eLoc == SVX_SHADOW_TOPRIGHT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
+ if ( nMergeEndCol+1 > rPaintCol && nMergeEndCol < MAXCOL )
+ rPaintCol = nMergeEndCol+1;
+ if ( eLoc == SVX_SHADOW_BOTTOMLEFT || eLoc == SVX_SHADOW_BOTTOMRIGHT )
+ if ( nMergeEndRow+1 > rPaintRow && nMergeEndRow < MAXROW )
+ rPaintRow = nMergeEndRow+1;
+ }
+
+ if (bRefresh)
+ {
+ if ( nMergeEndCol > nThisCol )
+ pDocument->ApplyFlagsTab( nThisCol+1, nThisRow, nMergeEndCol, pData[i].nRow,
+ nTab, SC_MF_HOR );
+ if ( nMergeEndRow > nThisRow )
+ pDocument->ApplyFlagsTab( nThisCol, nThisRow+1, nThisCol, nMergeEndRow,
+ nTab, SC_MF_VER );
+ if ( nMergeEndCol > nThisCol && nMergeEndRow > nThisRow )
+ pDocument->ApplyFlagsTab( nThisCol+1, nThisRow+1, nMergeEndCol, nMergeEndRow,
+ nTab, SC_MF_HOR | SC_MF_VER );
+
+ Search( nThisRow, i ); // Daten wurden veraendert
+ Search( nStartRow, nStartIndex );
+ Search( nEndRow, nEndIndex );
+ }
+ }
+ }
+
+ return bFound;
+}
+
+
+BOOL ScAttrArray::RemoveAreaMerge(SCROW nStartRow, SCROW nEndRow)
+{
+ BOOL bFound = FALSE;
+ const ScPatternAttr* pPattern;
+ const ScMergeAttr* pItem;
+ SCSIZE nIndex;
+
+ Search( nStartRow, nIndex );
+ SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
+ if (nThisStart < nStartRow)
+ nThisStart = nStartRow;
+
+ while ( nThisStart <= nEndRow )
+ {
+ SCROW nThisEnd = pData[nIndex].nRow;
+ if (nThisEnd > nEndRow)
+ nThisEnd = nEndRow;
+
+ pPattern = pData[nIndex].pPattern;
+ pItem = (const ScMergeAttr*) &pPattern->GetItem( ATTR_MERGE );
+ SCsCOL nCountX = pItem->GetColMerge();
+ SCsROW nCountY = pItem->GetRowMerge();
+ if (nCountX>1 || nCountY>1)
+ {
+ const ScMergeAttr* pAttr = (const ScMergeAttr*)
+ &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
+ const ScMergeFlagAttr* pFlagAttr = (const ScMergeFlagAttr*)
+ &pDocument->GetPool()->GetDefaultItem( ATTR_MERGE_FLAG );
+
+ DBG_ASSERT( nCountY==1 || nThisStart==nThisEnd, "was'n hier los?" );
+
+ SCCOL nThisCol = nCol;
+ SCCOL nMergeEndCol = nThisCol + nCountX - 1;
+ SCROW nMergeEndRow = nThisEnd + nCountY - 1;
+
+ //! ApplyAttr fuer Bereiche !!!
+
+ for (SCROW nThisRow = nThisStart; nThisRow <= nThisEnd; nThisRow++)
+ pDocument->ApplyAttr( nThisCol, nThisRow, nTab, *pAttr );
+
+ ScPatternAttr* pNewPattern = new ScPatternAttr( pDocument->GetPool() );
+ SfxItemSet* pSet = &pNewPattern->GetItemSet();
+ pSet->Put( *pFlagAttr );
+ pDocument->ApplyPatternAreaTab( nThisCol, nThisStart, nMergeEndCol, nMergeEndRow,
+ nTab, *pNewPattern );
+ delete pNewPattern;
+
+ Search( nThisEnd, nIndex ); // Daten wurden veraendert !!!
+ }
+
+ ++nIndex;
+ if ( nIndex < nCount )
+ nThisStart = pData[nIndex-1].nRow+1;
+ else
+ nThisStart = MAXROW+1; // Ende
+ }
+
+ return bFound;
+}
+
+ // Bereich loeschen, aber Merge-Flags stehenlassen
+
+void ScAttrArray::DeleteAreaSafe(SCROW nStartRow, SCROW nEndRow)
+{
+ SetPatternAreaSafe( nStartRow, nEndRow, pDocument->GetDefPattern(), TRUE );
+}
+
+
+void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
+ const ScPatternAttr* pWantedPattern, BOOL bDefault )
+{
+ const ScPatternAttr* pOldPattern;
+ const ScMergeFlagAttr* pItem;
+
+ SCSIZE nIndex;
+ SCROW nRow;
+ SCROW nThisRow;
+ BOOL bFirstUse = TRUE;
+
+ Search( nStartRow, nIndex );
+ nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
+ while ( nThisRow <= nEndRow )
+ {
+ pOldPattern = pData[nIndex].pPattern;
+ if (pOldPattern != pWantedPattern) //! else-Zweig ?
+ {
+ if (nThisRow < nStartRow) nThisRow = nStartRow;
+ nRow = pData[nIndex].nRow;
+ SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
+ pItem = (const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG );
+
+ if (pItem->IsOverlapped() || pItem->HasAutoFilter())
+ {
+ // #108045# default-constructing a ScPatternAttr for DeleteArea doesn't work
+ // because it would have no cell style information.
+ // Instead, the document's GetDefPattern is copied. Since it is passed as
+ // pWantedPattern, no special treatment of default is needed here anymore.
+ ScPatternAttr* pNewPattern = new ScPatternAttr( *pWantedPattern );
+ SfxItemSet* pSet = &pNewPattern->GetItemSet();
+ pSet->Put( *pItem );
+ SetPatternArea( nThisRow, nAttrRow, pNewPattern, TRUE );
+ delete pNewPattern;
+ }
+ else
+ {
+ if ( !bDefault )
+ {
+ if (bFirstUse)
+ bFirstUse = FALSE;
+ else
+ pDocument->GetPool()->Put( *pWantedPattern ); // im Pool ist es schon!
+ }
+ SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
+ }
+
+ Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
+ }
+
+ ++nIndex;
+ nThisRow = pData[nIndex-1].nRow+1;
+ }
+}
+
+
+BOOL ScAttrArray::ApplyFlags( SCROW nStartRow, SCROW nEndRow, INT16 nFlags )
+{
+ const ScPatternAttr* pOldPattern;
+
+ INT16 nOldValue;
+ SCSIZE nIndex;
+ SCROW nRow;
+ SCROW nThisRow;
+ BOOL bChanged = FALSE;
+
+ Search( nStartRow, nIndex );
+ nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
+ if (nThisRow < nStartRow) nThisRow = nStartRow;
+
+ while ( nThisRow <= nEndRow )
+ {
+ pOldPattern = pData[nIndex].pPattern;
+ nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
+ if ( (nOldValue | nFlags) != nOldValue )
+ {
+ nRow = pData[nIndex].nRow;
+ SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
+ ScPatternAttr aNewPattern(*pOldPattern);
+ aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue | nFlags ) );
+ SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
+ Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
+ bChanged = TRUE;
+ }
+
+ ++nIndex;
+ nThisRow = pData[nIndex-1].nRow+1;
+ }
+
+ return bChanged;
+}
+
+
+BOOL ScAttrArray::RemoveFlags( SCROW nStartRow, SCROW nEndRow, INT16 nFlags )
+{
+ const ScPatternAttr* pOldPattern;
+
+ INT16 nOldValue;
+ SCSIZE nIndex;
+ SCROW nRow;
+ SCROW nThisRow;
+ BOOL bChanged = FALSE;
+
+ Search( nStartRow, nIndex );
+ nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
+ if (nThisRow < nStartRow) nThisRow = nStartRow;
+
+ while ( nThisRow <= nEndRow )
+ {
+ pOldPattern = pData[nIndex].pPattern;
+ nOldValue = ((const ScMergeFlagAttr*) &pOldPattern->GetItem( ATTR_MERGE_FLAG ))->GetValue();
+ if ( (nOldValue & ~nFlags) != nOldValue )
+ {
+ nRow = pData[nIndex].nRow;
+ SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
+ ScPatternAttr aNewPattern(*pOldPattern);
+ aNewPattern.GetItemSet().Put( ScMergeFlagAttr( nOldValue & ~nFlags ) );
+ SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
+ Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
+ bChanged = TRUE;
+ }
+
+ ++nIndex;
+ nThisRow = pData[nIndex-1].nRow+1;
+ }
+
+ return bChanged;
+}
+
+
+void ScAttrArray::ClearItems( SCROW nStartRow, SCROW nEndRow, const USHORT* pWhich )
+{
+ const ScPatternAttr* pOldPattern;
+
+ SCSIZE nIndex;
+ SCROW nRow;
+ SCROW nThisRow;
+
+ Search( nStartRow, nIndex );
+ nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
+ if (nThisRow < nStartRow) nThisRow = nStartRow;
+
+ while ( nThisRow <= nEndRow )
+ {
+ pOldPattern = pData[nIndex].pPattern;
+ if ( pOldPattern->HasItemsSet( pWhich ) )
+ {
+ ScPatternAttr aNewPattern(*pOldPattern);
+ aNewPattern.ClearItems( pWhich );
+
+ nRow = pData[nIndex].nRow;
+ SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
+ SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
+ Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
+ }
+
+ ++nIndex;
+ nThisRow = pData[nIndex-1].nRow+1;
+ }
+}
+
+
+void ScAttrArray::ChangeIndent( SCROW nStartRow, SCROW nEndRow, BOOL bIncrement )
+{
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ SCROW nThisStart = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
+ if (nThisStart < nStartRow) nThisStart = nStartRow;
+
+ while ( nThisStart <= nEndRow )
+ {
+ const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
+ const SfxItemSet& rOldSet = pOldPattern->GetItemSet();
+ const SfxPoolItem* pItem;
+
+ BOOL bNeedJust = ( rOldSet.GetItemState( ATTR_HOR_JUSTIFY, FALSE, &pItem ) != SFX_ITEM_SET
+ || ((const SvxHorJustifyItem*)pItem)->GetValue() != SVX_HOR_JUSTIFY_LEFT );
+ USHORT nOldValue = ((const SfxUInt16Item&)rOldSet.Get( ATTR_INDENT )).GetValue();
+ USHORT nNewValue = nOldValue;
+ if ( bIncrement )
+ {
+ if ( nNewValue < SC_MAX_INDENT )
+ {
+ nNewValue += SC_INDENT_STEP;
+ if ( nNewValue > SC_MAX_INDENT ) nNewValue = SC_MAX_INDENT;
+ }
+ }
+ else
+ {
+ if ( nNewValue > 0 )
+ {
+ if ( nNewValue > SC_INDENT_STEP )
+ nNewValue -= SC_INDENT_STEP;
+ else
+ nNewValue = 0;
+ }
+ }
+
+ if ( bNeedJust || nNewValue != nOldValue )
+ {
+ SCROW nThisEnd = pData[nIndex].nRow;
+ SCROW nAttrRow = Min( nThisEnd, nEndRow );
+ ScPatternAttr aNewPattern(*pOldPattern);
+ aNewPattern.GetItemSet().Put( SfxUInt16Item( ATTR_INDENT, nNewValue ) );
+ if ( bNeedJust )
+ aNewPattern.GetItemSet().Put(
+ SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
+ SetPatternArea( nThisStart, nAttrRow, &aNewPattern, TRUE );
+
+ nThisStart = nThisEnd + 1;
+ Search( nThisStart, nIndex ); // Daten wurden veraendert !!!
+ }
+ else
+ {
+ nThisStart = pData[nIndex].nRow + 1; // weiterzaehlen...
+ ++nIndex;
+ }
+ }
+}
+
+
+SCsROW ScAttrArray::GetNextUnprotected( SCsROW nRow, BOOL bUp ) const
+{
+ long nRet = nRow;
+ if (VALIDROW(nRow))
+ {
+ SCSIZE nIndex;
+ Search(nRow, nIndex);
+ while (((const ScProtectionAttr&)pData[nIndex].pPattern->
+ GetItem(ATTR_PROTECTION)).GetProtection())
+ {
+ if (bUp)
+ {
+ if (nIndex==0)
+ return -1; // nichts gefunden
+ --nIndex;
+ nRet = pData[nIndex].nRow;
+ }
+ else
+ {
+ nRet = pData[nIndex].nRow+1;
+ ++nIndex;
+ if (nIndex>=nCount)
+ return MAXROW+1; // nichts gefunden
+ }
+ }
+ }
+ return nRet;
+}
+
+
+void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, BOOL* pUsed, BOOL bReset )
+{
+ SCROW nStart = 0;
+ SCSIZE nPos = 0;
+ while (nPos < nCount)
+ {
+ SCROW nEnd = pData[nPos].nRow;
+ if (pData[nPos].pPattern->GetStyleSheet() == pStyleSheet)
+ {
+// for (SCROW nRow = nStart; nRow <= nEnd; nRow++)
+// pUsed[nRow] = TRUE;
+
+ memset( &pUsed[nStart], TRUE, nEnd-nStart+1 );
+
+ if (bReset)
+ {
+ ScPatternAttr* pNewPattern = new ScPatternAttr(*pData[nPos].pPattern);
+ pDocument->GetPool()->Remove(*pData[nPos].pPattern);
+ pNewPattern->SetStyleSheet( (ScStyleSheet*)
+ pDocument->GetStyleSheetPool()->
+ Find( ScGlobal::GetRscString(STR_STYLENAME_STANDARD),
+ SFX_STYLE_FAMILY_PARA,
+ SFXSTYLEBIT_AUTO | SCSTYLEBIT_STANDARD ) );
+ pData[nPos].pPattern = (const ScPatternAttr*)
+ &pDocument->GetPool()->Put(*pNewPattern);
+ delete pNewPattern;
+
+ if (Concat(nPos))
+ {
+ Search(nStart, nPos);
+ --nPos; // wegen ++ am Ende
+ }
+ }
+ }
+ nStart = nEnd + 1;
+ ++nPos;
+ }
+}
+
+
+BOOL ScAttrArray::IsStyleSheetUsed( const ScStyleSheet& rStyle,
+ BOOL bGatherAllStyles ) const
+{
+ BOOL bIsUsed = FALSE;
+ SCSIZE nPos = 0;
+
+ while ( nPos < nCount )
+ {
+ const ScStyleSheet* pStyle = pData[nPos].pPattern->GetStyleSheet();
+ if ( pStyle )
+ {
+ pStyle->SetUsage( ScStyleSheet::USED );
+ if ( pStyle == &rStyle )
+ {
+ if ( !bGatherAllStyles )
+ return TRUE;
+ bIsUsed = TRUE;
+ }
+ }
+ nPos++;
+ }
+
+ return bIsUsed;
+}
+
+
+BOOL ScAttrArray::IsEmpty() const
+{
+ if (nCount == 1)
+ {
+ if ( pData[0].pPattern != pDocument->GetDefPattern() )
+ return FALSE;
+ else
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+
+//UNUSED2008-05 SCROW ScAttrArray::GetFirstEntryPos() const
+//UNUSED2008-05 {
+//UNUSED2008-05 DBG_ASSERT( nCount, "nCount = 0" );
+//UNUSED2008-05
+//UNUSED2008-05 if ( pData[0].pPattern != pDocument->GetDefPattern() )
+//UNUSED2008-05 return 0;
+//UNUSED2008-05 else
+//UNUSED2008-05 {
+//UNUSED2008-05 if (nCount==1)
+//UNUSED2008-05 return 0; // leer
+//UNUSED2008-05 else
+//UNUSED2008-05 return pData[0].nRow + 1;
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05
+//UNUSED2008-05 SCROW ScAttrArray::GetLastEntryPos( BOOL bIncludeBottom ) const
+//UNUSED2008-05 {
+//UNUSED2008-05 DBG_ASSERT( nCount, "nCount == 0" );
+//UNUSED2008-05
+//UNUSED2008-05 if (bIncludeBottom)
+//UNUSED2008-05 bIncludeBottom = ( pData[nCount-1].pPattern != pDocument->GetDefPattern() );
+//UNUSED2008-05
+//UNUSED2008-05 if (bIncludeBottom)
+//UNUSED2008-05 return MAXROW;
+//UNUSED2008-05 else
+//UNUSED2008-05 {
+//UNUSED2008-05 if (nCount<=1)
+//UNUSED2008-05 return 0; // leer
+//UNUSED2008-05 else
+//UNUSED2008-05 return pData[nCount-2].nRow;
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+
+
+BOOL ScAttrArray::GetFirstVisibleAttr( SCROW& rFirstRow ) const
+{
+ DBG_ASSERT( nCount, "nCount == 0" );
+
+ BOOL bFound = FALSE;
+ SCSIZE nStart = 0;
+
+ // Skip first entry if more than 1 row.
+ // Entries at the end are not skipped, GetFirstVisibleAttr may be larger than GetLastVisibleAttr.
+
+ SCSIZE nVisStart = 1;
+ while ( nVisStart < nCount && pData[nVisStart].pPattern->IsVisibleEqual(*pData[nVisStart-1].pPattern) )
+ ++nVisStart;
+ if ( nVisStart >= nCount || pData[nVisStart-1].nRow > 0 ) // more than 1 row?
+ nStart = nVisStart;
+
+ while ( nStart < nCount && !bFound )
+ {
+ if ( pData[nStart].pPattern->IsVisible() )
+ {
+ rFirstRow = nStart ? ( pData[nStart-1].nRow + 1 ) : 0;
+ bFound = TRUE;
+ }
+ else
+ ++nStart;
+ }
+
+ return bFound;
+}
+
+// size (rows) of a range of attributes after cell content where the search is stopped
+// (more than a default page size, 2*42 because it's as good as any number)
+
+const SCROW SC_VISATTR_STOP = 84;
+
+BOOL ScAttrArray::GetLastVisibleAttr( SCROW& rLastRow, SCROW nLastData ) const
+{
+ // #i30830# changed behavior:
+ // ignore all attributes starting with the first run of SC_VISATTR_STOP equal rows
+ // below the last content cell
+
+ if ( nLastData == MAXROW )
+ {
+ rLastRow = MAXROW; // can't look for attributes below MAXROW
+ return TRUE;
+ }
+
+ BOOL bFound = FALSE;
+
+ // loop backwards from the end instead of using Search, assuming that
+ // there usually aren't many attributes below the last cell
+
+ SCSIZE nPos = nCount;
+ while ( nPos > 0 && pData[nPos-1].nRow > nLastData )
+ {
+ SCSIZE nEndPos = nPos - 1;
+ SCSIZE nStartPos = nEndPos; // find range of visually equal formats
+ while ( nStartPos > 0 &&
+ pData[nStartPos-1].nRow > nLastData &&
+ pData[nStartPos-1].pPattern->IsVisibleEqual(*pData[nStartPos].pPattern) )
+ --nStartPos;
+
+ SCROW nAttrStartRow = ( nStartPos > 0 ) ? ( pData[nStartPos-1].nRow + 1 ) : 0;
+ if ( nAttrStartRow <= nLastData )
+ nAttrStartRow = nLastData + 1;
+ SCROW nAttrSize = pData[nEndPos].nRow + 1 - nAttrStartRow;
+ if ( nAttrSize >= SC_VISATTR_STOP )
+ {
+ bFound = FALSE; // ignore this range and below
+ }
+ else if ( !bFound && pData[nEndPos].pPattern->IsVisible() )
+ {
+ rLastRow = pData[nEndPos].nRow;
+ bFound = TRUE;
+ }
+
+ nPos = nStartPos; // look further from the top of the range
+ }
+
+ return bFound;
+}
+
+
+BOOL ScAttrArray::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
+{
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ SCROW nThisStart = nStartRow;
+ BOOL bFound = FALSE;
+ while ( nIndex < nCount && nThisStart <= nEndRow && !bFound )
+ {
+ if ( pData[nIndex].pPattern->IsVisible() )
+ bFound = TRUE;
+
+ nThisStart = pData[nIndex].nRow + 1;
+ ++nIndex;
+ }
+
+ return bFound;
+}
+
+
+BOOL ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
+ SCROW nStartRow, SCROW nEndRow ) const
+{
+ BOOL bEqual = TRUE;
+ SCSIZE nThisPos = 0;
+ SCSIZE nOtherPos = 0;
+ if ( nStartRow > 0 )
+ {
+ Search( nStartRow, nThisPos );
+ rOther.Search( nStartRow, nOtherPos );
+ }
+
+ while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
+ {
+ SCROW nThisRow = pData[nThisPos].nRow;
+ SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
+ const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
+ const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
+ bEqual = ( pThisPattern == pOtherPattern ||
+ pThisPattern->IsVisibleEqual(*pOtherPattern) );
+
+ if ( nThisRow >= nOtherRow )
+ {
+ if ( nOtherRow >= nEndRow ) break;
+ ++nOtherPos;
+ }
+ if ( nThisRow <= nOtherRow )
+ {
+ if ( nThisRow >= nEndRow ) break;
+ ++nThisPos;
+ }
+ }
+
+ return bEqual;
+}
+
+
+BOOL ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW nEndRow ) const
+{
+ //! mit IsVisibleEqual zusammenfassen?
+
+ BOOL bEqual = TRUE;
+ SCSIZE nThisPos = 0;
+ SCSIZE nOtherPos = 0;
+ if ( nStartRow > 0 )
+ {
+ Search( nStartRow, nThisPos );
+ rOther.Search( nStartRow, nOtherPos );
+ }
+
+ while ( nThisPos<nCount && nOtherPos<rOther.nCount && bEqual )
+ {
+ SCROW nThisRow = pData[nThisPos].nRow;
+ SCROW nOtherRow = rOther.pData[nOtherPos].nRow;
+ const ScPatternAttr* pThisPattern = pData[nThisPos].pPattern;
+ const ScPatternAttr* pOtherPattern = rOther.pData[nOtherPos].pPattern;
+ bEqual = ( pThisPattern == pOtherPattern );
+
+ if ( nThisRow >= nOtherRow )
+ {
+ if ( nOtherRow >= nEndRow ) break;
+ ++nOtherPos;
+ }
+ if ( nThisRow <= nOtherRow )
+ {
+ if ( nThisRow >= nEndRow ) break;
+ ++nThisPos;
+ }
+ }
+
+ return bEqual;
+}
+
+
+BOOL ScAttrArray::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
+{
+ // horizontal zusammengefasste duerfen nicht herausgeschoben werden
+ // (ob die ganze Zusammenfassung betroffen ist, ist hier nicht zu erkennen)
+
+ BOOL bTest = TRUE;
+ if (!IsEmpty())
+ {
+ SCSIZE nIndex = 0;
+ if ( nStartRow > 0 )
+ Search( nStartRow, nIndex );
+
+ for ( ; nIndex < nCount; nIndex++ )
+ {
+ if ( ((const ScMergeFlagAttr&)pData[nIndex].pPattern->
+ GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped() )
+ {
+ bTest = FALSE; // darf nicht herausgeschoben werden
+ break;
+ }
+ if ( pData[nIndex].nRow >= nEndRow ) // Ende des Bereichs
+ break;
+ }
+ }
+ return bTest;
+}
+
+
+BOOL ScAttrArray::TestInsertRow( SCSIZE nSize ) const
+{
+ // wenn die erste herausgeschobene Zeile vertikal ueberlappt ist,
+ // wuerde eine kaputte Zusammenfassung uebrigbleiben
+
+ if (pData)
+ {
+ // MAXROW + 1 - nSize = erste herausgeschobene Zeile
+
+ SCSIZE nFirstLost = nCount-1;
+ while ( nFirstLost && pData[nFirstLost-1].nRow >= sal::static_int_cast<SCROW>(MAXROW + 1 - nSize) )
+ --nFirstLost;
+
+ if ( ((const ScMergeFlagAttr&)pData[nFirstLost].pPattern->
+ GetItem(ATTR_MERGE_FLAG)).IsVerOverlapped() )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+void ScAttrArray::InsertRow( SCROW nStartRow, SCSIZE nSize )
+{
+ if (!pData)
+ return;
+
+ SCROW nSearch = nStartRow > 0 ? nStartRow - 1 : 0; // Vorgaenger erweitern
+ SCSIZE nIndex;
+ Search( nSearch, nIndex );
+
+ // ein gesetztes ScMergeAttr darf nicht ausgedehnt werden
+ // (darum hinterher wieder loeschen)
+
+ BOOL bDoMerge = ((const ScMergeAttr&) pData[nIndex].pPattern->GetItem(ATTR_MERGE)).IsMerged();
+
+ SCSIZE nRemove = 0;
+ SCSIZE i;
+ for (i = nIndex; i < nCount-1; i++)
+ {
+ SCROW nNew = pData[i].nRow + nSize;
+ if ( nNew >= MAXROW ) // Ende erreicht ?
+ {
+ nNew = MAXROW;
+ if (!nRemove)
+ nRemove = i+1; // folgende loeschen
+ }
+ pData[i].nRow = nNew;
+ }
+
+ // muessen Eintraege am Ende geloescht werden?
+
+ if (nRemove && nRemove < nCount)
+ DeleteRange( nRemove, nCount-1 );
+
+ if (bDoMerge) // ausgedehntes ScMergeAttr wieder reparieren
+ {
+ //! ApplyAttr fuer Bereiche !!!
+
+ const SfxPoolItem& rDef = pDocument->GetPool()->GetDefaultItem( ATTR_MERGE );
+ for (SCSIZE nAdd=0; nAdd<nSize; nAdd++)
+ pDocument->ApplyAttr( nCol, nStartRow+nAdd, nTab, rDef );
+
+ // im eingefuegten Bereich ist nichts zusammengefasst
+ }
+
+ // Don't duplicate the merge flags in the inserted row.
+ // #i108488# SC_MF_SCENARIO has to be allowed.
+ RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO | SC_MF_BUTTON );
+}
+
+
+void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
+{
+ if (pData)
+ {
+ BOOL bFirst=TRUE;
+ SCSIZE nStartIndex = 0;
+ SCSIZE nEndIndex = 0;
+ SCSIZE i;
+
+ for ( i = 0; i < nCount-1; i++)
+ if (pData[i].nRow >= nStartRow && pData[i].nRow <= sal::static_int_cast<SCROW>(nStartRow+nSize-1))
+ {
+ if (bFirst)
+ {
+ nStartIndex = i;
+ bFirst = FALSE;
+ }
+ nEndIndex = i;
+ }
+ if (!bFirst)
+ {
+ SCROW nStart;
+ if (nStartIndex==0)
+ nStart = 0;
+ else
+ nStart = pData[nStartIndex-1].nRow + 1;
+
+ if (nStart < nStartRow)
+ {
+ pData[nStartIndex].nRow = nStartRow - 1;
+ ++nStartIndex;
+ }
+ if (nEndIndex >= nStartIndex)
+ {
+ DeleteRange( nStartIndex, nEndIndex );
+ if (nStartIndex > 0)
+ if ( pData[nStartIndex-1].pPattern == pData[nStartIndex].pPattern )
+ DeleteRange( nStartIndex-1, nStartIndex-1 );
+ }
+ }
+ for (i = 0; i < nCount-1; i++)
+ if (pData[i].nRow >= nStartRow)
+ pData[i].nRow -= nSize;
+
+// unten nicht Default-Pattern nachschieben, um Druckbereiche erkennen zu koennen
+// stattdessen nur Merge-Flags loeschen
+
+ RemoveFlags( MAXROW-nSize+1, MAXROW, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
+ }
+}
+
+
+void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
+{
+ ScDocumentPool* pDocPool = pDocument->GetPool();
+ for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
+ pDocPool->Remove(*pData[i].pPattern);
+
+ memmove( &pData[nStartIndex], &pData[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ScAttrEntry) );
+ nCount -= nEndIndex-nStartIndex+1;
+}
+
+
+void ScAttrArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
+{
+ RemoveAreaMerge( nStartRow, nEndRow ); // von zusammengefassten auch die Flags loeschen
+
+ if ( !HasAttrib( nStartRow, nEndRow, HASATTR_OVERLAPPED | HASATTR_AUTOFILTER) )
+ SetPatternArea( nStartRow, nEndRow, pDocument->GetDefPattern() );
+ else
+ DeleteAreaSafe( nStartRow, nEndRow ); // Merge-Flags stehenlassen
+}
+
+
+void ScAttrArray::DeleteHardAttr(SCROW nStartRow, SCROW nEndRow)
+{
+ const ScPatternAttr* pDefPattern = pDocument->GetDefPattern();
+ const ScPatternAttr* pOldPattern;
+
+ SCSIZE nIndex;
+ SCROW nRow;
+ SCROW nThisRow;
+
+ Search( nStartRow, nIndex );
+ nThisRow = (nIndex>0) ? pData[nIndex-1].nRow+1 : 0;
+ if (nThisRow < nStartRow) nThisRow = nStartRow;
+
+ while ( nThisRow <= nEndRow )
+ {
+ pOldPattern = pData[nIndex].pPattern;
+
+ if ( pOldPattern->GetItemSet().Count() ) // harte Attribute ?
+ {
+ nRow = pData[nIndex].nRow;
+ SCROW nAttrRow = Min( (SCROW)nRow, (SCROW)nEndRow );
+
+ ScPatternAttr aNewPattern(*pOldPattern);
+ SfxItemSet& rSet = aNewPattern.GetItemSet();
+ for (USHORT nId = ATTR_PATTERN_START; nId <= ATTR_PATTERN_END; nId++)
+ if (nId != ATTR_MERGE && nId != ATTR_MERGE_FLAG)
+ rSet.ClearItem(nId);
+
+ if ( aNewPattern == *pDefPattern )
+ SetPatternArea( nThisRow, nAttrRow, pDefPattern, FALSE );
+ else
+ SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
+
+ Search( nThisRow, nIndex ); // Daten wurden veraendert !!!
+ }
+
+ ++nIndex;
+ nThisRow = pData[nIndex-1].nRow+1;
+ }
+}
+
+ // Verschieben innerhalb eines Dokuments
+
+void ScAttrArray::MoveTo(SCROW nStartRow, SCROW nEndRow, ScAttrArray& rAttrArray)
+{
+ SCROW nStart = nStartRow;
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ if ((pData[i].nRow >= nStartRow) && ((i==0) ? TRUE : pData[i-1].nRow < nEndRow))
+ {
+ // Kopieren (bPutToPool=TRUE)
+ rAttrArray.SetPatternArea( nStart, Min( (SCROW)pData[i].nRow, (SCROW)nEndRow ),
+ pData[i].pPattern, TRUE );
+ }
+ nStart = Max( (SCROW)nStart, (SCROW)(pData[i].nRow + 1) );
+ }
+ DeleteArea(nStartRow, nEndRow);
+}
+
+
+ // Kopieren zwischen Dokumenten (Clipboard)
+
+void ScAttrArray::CopyArea( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray,
+ INT16 nStripFlags )
+{
+ nStartRow -= nDy; // Source
+ nEndRow -= nDy;
+
+ SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
+ SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
+
+ ScDocumentPool* pSourceDocPool = pDocument->GetPool();
+ ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
+ BOOL bSamePool = (pSourceDocPool==pDestDocPool);
+
+ for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
+ {
+ if (pData[i].nRow >= nStartRow)
+ {
+ const ScPatternAttr* pOldPattern = pData[i].pPattern;
+ const ScPatternAttr* pNewPattern;
+
+ if (IsDefaultItem( pOldPattern ))
+ {
+ // am Default muss nichts veraendert werden
+
+ pNewPattern = (const ScPatternAttr*)
+ &pDestDocPool->GetDefaultItem( ATTR_PATTERN );
+ }
+ else if ( nStripFlags )
+ {
+ ScPatternAttr* pTmpPattern = new ScPatternAttr( *pOldPattern );
+ INT16 nNewFlags = 0;
+ if ( nStripFlags != SC_MF_ALL )
+ nNewFlags = ((const ScMergeFlagAttr&)pTmpPattern->GetItem(ATTR_MERGE_FLAG)).
+ GetValue() & ~nStripFlags;
+
+ if ( nNewFlags )
+ pTmpPattern->GetItemSet().Put( ScMergeFlagAttr( nNewFlags ) );
+ else
+ pTmpPattern->GetItemSet().ClearItem( ATTR_MERGE_FLAG );
+
+ if (bSamePool)
+ pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pTmpPattern);
+ else
+ pNewPattern = pTmpPattern->PutInPool( rAttrArray.pDocument, pDocument );
+ delete pTmpPattern;
+ }
+ else
+ {
+ if (bSamePool)
+ pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
+ else
+ pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
+ }
+
+ rAttrArray.SetPatternArea(nDestStart,
+ Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern);
+ }
+
+ // when pasting from clipboard and skipping filtered rows, the adjusted end position
+ // can be negative
+ nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
+ }
+}
+
+ // Flags stehenlassen
+ //! mit CopyArea zusammenfassen !!!
+
+void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, long nDy, ScAttrArray& rAttrArray )
+{
+ nStartRow -= nDy; // Source
+ nEndRow -= nDy;
+
+ SCROW nDestStart = Max((long)((long)nStartRow + nDy), (long) 0);
+ SCROW nDestEnd = Min((long)((long)nEndRow + nDy), (long) MAXROW);
+
+ if ( !rAttrArray.HasAttrib( nDestStart, nDestEnd, HASATTR_OVERLAPPED ) )
+ {
+ CopyArea( nStartRow+nDy, nEndRow+nDy, nDy, rAttrArray );
+ return;
+ }
+
+ ScDocumentPool* pSourceDocPool = pDocument->GetPool();
+ ScDocumentPool* pDestDocPool = rAttrArray.pDocument->GetPool();
+ BOOL bSamePool = (pSourceDocPool==pDestDocPool);
+
+ for (SCSIZE i = 0; (i < nCount) && (nDestStart <= nDestEnd); i++)
+ {
+ if (pData[i].nRow >= nStartRow)
+ {
+ const ScPatternAttr* pOldPattern = pData[i].pPattern;
+ const ScPatternAttr* pNewPattern;
+
+ if (bSamePool)
+ pNewPattern = (ScPatternAttr*) &pDestDocPool->Put(*pOldPattern);
+ else
+ pNewPattern = pOldPattern->PutInPool( rAttrArray.pDocument, pDocument );
+
+ rAttrArray.SetPatternAreaSafe(nDestStart,
+ Min((SCROW)(pData[i].nRow + nDy), nDestEnd), pNewPattern, FALSE);
+ }
+
+ // when pasting from clipboard and skipping filtered rows, the adjusted end position
+ // can be negative
+ nDestStart = Max((long)nDestStart, (long)(pData[i].nRow + nDy + 1));
+ }
+}
+
+
+SCsROW ScAttrArray::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
+ BOOL bUp, ScMarkArray* pMarkArray )
+{
+ BOOL bFound = FALSE;
+
+ if (pMarkArray)
+ {
+ nRow = pMarkArray->GetNextMarked( nRow, bUp );
+ if (!VALIDROW(nRow))
+ return nRow;
+ }
+
+ SCSIZE nIndex;
+ Search(nRow, nIndex);
+ const ScPatternAttr* pPattern = pData[nIndex].pPattern;
+
+ while (nIndex < nCount && !bFound)
+ {
+ if (pPattern->GetStyleSheet() == pSearchStyle)
+ {
+ if (pMarkArray)
+ {
+ nRow = pMarkArray->GetNextMarked( nRow, bUp );
+ SCROW nStart = nIndex ? pData[nIndex-1].nRow+1 : 0;
+ if (nRow >= nStart && nRow <= pData[nIndex].nRow)
+ bFound = TRUE;
+ }
+ else
+ bFound = TRUE;
+ }
+
+ if (!bFound)
+ {
+ if (bUp)
+ {
+ if (nIndex==0)
+ {
+ nIndex = nCount;
+ nRow = -1;
+ }
+ else
+ {
+ --nIndex;
+ nRow = pData[nIndex].nRow;
+ pPattern = pData[nIndex].pPattern;
+ }
+ }
+ else
+ {
+ nRow = pData[nIndex].nRow+1;
+ ++nIndex;
+ if (nIndex<nCount)
+ pPattern = pData[nIndex].pPattern;
+ }
+ }
+ }
+
+ DBG_ASSERT( bFound || !ValidRow(nRow), "interner Fehler in ScAttrArray::SearchStyle" );
+
+ return nRow;
+}
+
+
+BOOL ScAttrArray::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow,
+ const ScStyleSheet* pSearchStyle, BOOL bUp, ScMarkArray* pMarkArray )
+{
+ SCsROW nStartRow = SearchStyle( rRow, pSearchStyle, bUp, pMarkArray );
+ if (VALIDROW(nStartRow))
+ {
+ SCSIZE nIndex;
+ Search(nStartRow,nIndex);
+
+ rRow = nStartRow;
+ if (bUp)
+ {
+ if (nIndex>0)
+ rEndRow = pData[nIndex-1].nRow + 1;
+ else
+ rEndRow = 0;
+ if (pMarkArray)
+ {
+ SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, TRUE );
+ if (nMarkEnd>rEndRow)
+ rEndRow = nMarkEnd;
+ }
+ }
+ else
+ {
+ rEndRow = pData[nIndex].nRow;
+ if (pMarkArray)
+ {
+ SCROW nMarkEnd = pMarkArray->GetMarkEnd( nStartRow, FALSE );
+ if (nMarkEnd<rEndRow)
+ rEndRow = nMarkEnd;
+ }
+ }
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+//------------------------------------------------------------------------
+//
+// Laden / Speichern
+//
+
+
+#if 0
+void ScAttrArray::Save( SvStream& /* rStream */ ) const
+{
+#if SC_ROWLIMIT_STREAM_ACCESS
+#error address types changed!
+ ScWriteHeader aHdr( rStream, 8 );
+
+ ScDocumentPool* pDocPool = pDocument->GetPool();
+
+ USHORT nSaveCount = nCount;
+ SCROW nSaveMaxRow = pDocument->GetSrcMaxRow();
+ if ( nSaveMaxRow != MAXROW )
+ {
+ if ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow )
+ {
+ pDocument->SetLostData(); // Warnung ausgeben
+ do
+ --nSaveCount;
+ while ( nSaveCount > 1 && pData[nSaveCount-2].nRow >= nSaveMaxRow );
+ }
+ }
+
+ rStream << nSaveCount;
+
+ const SfxPoolItem* pItem;
+ for (SCSIZE i=0; i<nSaveCount; i++)
+ {
+ rStream << Min( pData[i].nRow, nSaveMaxRow );
+
+ const ScPatternAttr* pPattern = pData[i].pPattern;
+ pDocPool->StoreSurrogate( rStream, pPattern );
+
+ // FALSE, weil ATTR_CONDITIONAL (noch) nicht in Vorlagen:
+ if (pPattern->GetItemSet().GetItemState(ATTR_CONDITIONAL,FALSE,&pItem) == SFX_ITEM_SET)
+ pDocument->SetConditionalUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
+
+ if (pPattern->GetItemSet().GetItemState(ATTR_VALIDDATA,FALSE,&pItem) == SFX_ITEM_SET)
+ pDocument->SetValidationUsed( ((const SfxUInt32Item*)pItem)->GetValue() );
+ }
+#endif // SC_ROWLIMIT_STREAM_ACCESS
+}
+
+
+void ScAttrArray::Load( SvStream& /* rStream */ )
+{
+#if SC_ROWLIMIT_STREAM_ACCESS
+#error address types changed!
+ ScDocumentPool* pDocPool = pDocument->GetPool();
+
+ ScReadHeader aHdr( rStream );
+
+ USHORT nNewCount;
+ rStream >> nNewCount;
+ if ( nNewCount > MAXROW+1 ) // wuerde das Array zu gross?
+ {
+ pDocument->SetLostData();
+ rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
+ return;
+ }
+
+ Reset( pDocument->GetDefPattern(), FALSE ); // loeschen
+ pData = new ScAttrEntry[nNewCount]; // neu anlegen
+ for (SCSIZE i=0; i<nNewCount; i++)
+ {
+ rStream >> pData[i].nRow;
+
+ USHORT nWhich = ATTR_PATTERN;
+ const ScPatternAttr* pNewPattern = (const ScPatternAttr*)
+ pDocPool->LoadSurrogate( rStream, nWhich, ATTR_PATTERN );
+ if (!pNewPattern)
+ {
+ // da is was schiefgelaufen
+ DBG_ERROR("ScAttrArray::Load: Surrogat nicht im Pool");
+ pNewPattern = pDocument->GetDefPattern();
+ }
+ ScDocumentPool::CheckRef( *pNewPattern );
+ pData[i].pPattern = pNewPattern;
+
+ // LoadSurrogate erhoeht auch die Ref
+ }
+ nCount = nLimit = nNewCount;
+
+ if ( nCount > 1 && pData[nCount-2].nRow >= MAXROW ) // faengt ein Attribut hinter MAXROW an?
+ {
+ pDocument->SetLostData();
+ rStream.SetError( SVSTREAM_FILEFORMAT_ERROR );
+ return;
+ }
+
+ if ( pDocument->GetSrcMaxRow() != MAXROW ) // Ende anpassen?
+ {
+ // Ende immer auf MAXROW umsetzen (nur auf 32 Bit)
+
+ DBG_ASSERT( pData[nCount-1].nRow == pDocument->GetSrcMaxRow(), "Attribut-Ende ?!?" );
+ pData[nCount-1].nRow = MAXROW;
+ }
+#endif // SC_ROWLIMIT_STREAM_ACCESS
+}
+#endif
+
+
+//UNUSED2008-05 void ScAttrArray::ConvertFontsAfterLoad()
+//UNUSED2008-05 {
+//UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter;
+//UNUSED2008-05 const ULONG nFlags = FONTTOSUBSFONT_IMPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
+//UNUSED2008-05 SCSIZE nIndex = 0;
+//UNUSED2008-05 SCROW nThisRow = 0;
+//UNUSED2008-05
+//UNUSED2008-05 while ( nThisRow <= MAXROW )
+//UNUSED2008-05 {
+//UNUSED2008-05 const ScPatternAttr* pOldPattern = pData[nIndex].pPattern;
+//UNUSED2008-05 const SfxPoolItem* pItem;
+//UNUSED2008-05 if( pOldPattern->GetItemSet().GetItemState( ATTR_FONT, FALSE, &pItem ) == SFX_ITEM_SET )
+//UNUSED2008-05 {
+//UNUSED2008-05 const SvxFontItem* pFontItem = (const SvxFontItem*) pItem;
+//UNUSED2008-05 const String& rOldName = pFontItem->GetFamilyName();
+//UNUSED2008-05 xFontConverter = CreateFontToSubsFontConverter( rOldName, nFlags );
+//UNUSED2008-05 if ( xFontConverter )
+//UNUSED2008-05 {
+//UNUSED2008-05 String aNewName( GetFontToSubsFontName( xFontConverter ) );
+//UNUSED2008-05 if ( aNewName != rOldName )
+//UNUSED2008-05 {
+//UNUSED2008-05 SCROW nAttrRow = pData[nIndex].nRow;
+//UNUSED2008-05 SvxFontItem aNewItem( pFontItem->GetFamily(), aNewName,
+//UNUSED2008-05 pFontItem->GetStyleName(), pFontItem->GetPitch(),
+//UNUSED2008-05 RTL_TEXTENCODING_DONTKNOW, ATTR_FONT );
+//UNUSED2008-05 ScPatternAttr aNewPattern( *pOldPattern );
+//UNUSED2008-05 aNewPattern.GetItemSet().Put( aNewItem );
+//UNUSED2008-05 SetPatternArea( nThisRow, nAttrRow, &aNewPattern, TRUE );
+//UNUSED2008-05 Search( nThisRow, nIndex ); //! data changed
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 ++nIndex;
+//UNUSED2008-05 nThisRow = pData[nIndex-1].nRow+1;
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+