summaryrefslogtreecommitdiff
path: root/sc/source/core/data
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/data')
-rw-r--r--sc/source/core/data/attarray.cxx2603
-rw-r--r--sc/source/core/data/attrib.cxx1331
-rw-r--r--sc/source/core/data/autonamecache.cxx111
-rw-r--r--sc/source/core/data/bcaslot.cxx720
-rw-r--r--sc/source/core/data/cell.cxx1987
-rw-r--r--sc/source/core/data/cell2.cxx1356
-rw-r--r--sc/source/core/data/column.cxx2186
-rw-r--r--sc/source/core/data/column2.cxx1859
-rw-r--r--sc/source/core/data/column3.cxx1878
-rw-r--r--sc/source/core/data/compressedarray.cxx909
-rw-r--r--sc/source/core/data/conditio.cxx1585
-rw-r--r--sc/source/core/data/dbdocutl.cxx200
-rw-r--r--sc/source/core/data/dociter.cxx1803
-rw-r--r--sc/source/core/data/docpool.cxx1042
-rw-r--r--sc/source/core/data/documen2.cxx1271
-rw-r--r--sc/source/core/data/documen3.cxx1937
-rw-r--r--sc/source/core/data/documen4.cxx1190
-rw-r--r--sc/source/core/data/documen5.cxx1014
-rw-r--r--sc/source/core/data/documen6.cxx187
-rw-r--r--sc/source/core/data/documen7.cxx524
-rw-r--r--sc/source/core/data/documen8.cxx1623
-rw-r--r--sc/source/core/data/documen9.cxx883
-rw-r--r--sc/source/core/data/document.cxx4471
-rw-r--r--sc/source/core/data/dpcachetable.cxx716
-rw-r--r--sc/source/core/data/dpdimsave.cxx587
-rw-r--r--sc/source/core/data/dpgroup.cxx1534
-rw-r--r--sc/source/core/data/dpobject.cxx2536
-rw-r--r--sc/source/core/data/dpoutput.cxx1961
-rw-r--r--sc/source/core/data/dpsave.cxx1127
-rw-r--r--sc/source/core/data/dpsdbtab.cxx330
-rw-r--r--sc/source/core/data/dpshttab.cxx308
-rw-r--r--sc/source/core/data/dptabdat.cxx336
-rw-r--r--sc/source/core/data/dptabres.cxx3677
-rw-r--r--sc/source/core/data/dptabsrc.cxx2725
-rw-r--r--sc/source/core/data/drawpage.cxx68
-rw-r--r--sc/source/core/data/drwlayer.cxx2063
-rw-r--r--sc/source/core/data/fillinfo.cxx1064
-rw-r--r--sc/source/core/data/global.cxx1964
-rw-r--r--sc/source/core/data/global2.cxx1250
-rw-r--r--sc/source/core/data/globalx.cxx174
-rw-r--r--sc/source/core/data/makefile.mk166
-rw-r--r--sc/source/core/data/markarr.cxx413
-rw-r--r--sc/source/core/data/markdata.cxx587
-rw-r--r--sc/source/core/data/olinetab.cxx811
-rw-r--r--sc/source/core/data/pagepar.cxx125
-rw-r--r--sc/source/core/data/patattr.cxx1337
-rw-r--r--sc/source/core/data/pivot.cxx2028
-rw-r--r--sc/source/core/data/pivot2.cxx521
-rw-r--r--sc/source/core/data/poolhelp.cxx89
-rw-r--r--sc/source/core/data/postit.cxx660
-rw-r--r--sc/source/core/data/scimpexpmsg.cxx116
-rw-r--r--sc/source/core/data/sortparam.cxx265
-rw-r--r--sc/source/core/data/stlpool.cxx643
-rw-r--r--sc/source/core/data/stlsheet.cxx342
-rw-r--r--sc/source/core/data/table1.cxx1486
-rw-r--r--sc/source/core/data/table2.cxx2861
-rw-r--r--sc/source/core/data/table3.cxx1833
-rw-r--r--sc/source/core/data/table4.cxx1986
-rw-r--r--sc/source/core/data/table5.cxx419
-rw-r--r--sc/source/core/data/table6.cxx693
-rw-r--r--sc/source/core/data/userdat.cxx130
-rw-r--r--sc/source/core/data/validat.cxx963
62 files changed, 73564 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..fc33c75306cc
--- /dev/null
+++ b/sc/source/core/data/attarray.cxx
@@ -0,0 +1,2603 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: attarray.cxx,v $
+ * $Revision: 1.25.32.2 $
+ *
+ * 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 <svx/boxitem.hxx>
+#include <svx/bolnitem.hxx>
+#include <svx/frmdiritem.hxx>
+#include <svx/shaditem.hxx>
+#include <svtools/poolcach.hxx>
+#include <svx/fontitem.hxx>
+#include <vcl/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;
+ }
+}
+
+//------------------------------------------------------------------------
+
+void ScAttrArray::TestData() const
+{
+#ifdef DBG_UTIL
+ 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 (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++;
+ }
+ }
+ }
+// 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));
+ }
+
+#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);
+ }
+
+#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
+ }
+
+ // Flags nicht duplizieren
+ //! direkt am Pattern testen ??
+ RemoveFlags( nStartRow, nStartRow+nSize-1, SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
+}
+
+
+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 }
+
diff --git a/sc/source/core/data/attrib.cxx b/sc/source/core/data/attrib.cxx
new file mode 100644
index 000000000000..a5f38c813d8c
--- /dev/null
+++ b/sc/source/core/data/attrib.cxx
@@ -0,0 +1,1331 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: attrib.cxx,v $
+ * $Revision: 1.19.32.4 $
+ *
+ * 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 ---------------------------------------------------------------
+
+
+#include <com/sun/star/util/CellProtection.hpp>
+#include <com/sun/star/util/XProtectable.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include "scitems.hxx"
+#include <svx/eeitem.hxx>
+
+#include <svx/boxitem.hxx>
+#include <svx/editdata.hxx>
+#include <svx/editeng.hxx>
+#include <svx/editobj.hxx>
+#include <svx/flditem.hxx>
+
+#include "attrib.hxx"
+#include "global.hxx"
+#include "editutil.hxx"
+#include "sc.hrc"
+#include "globstr.hrc"
+
+#include "textuno.hxx" // ScHeaderFooterContentObj
+
+using namespace com::sun::star;
+
+//------------------------------------------------------------------------
+
+TYPEINIT1(ScMergeAttr, SfxPoolItem);
+TYPEINIT1_AUTOFACTORY(ScProtectionAttr, SfxPoolItem);
+TYPEINIT1(ScRangeItem, SfxPoolItem);
+TYPEINIT1(ScTableListItem, SfxPoolItem);
+TYPEINIT1(ScPageHFItem, SfxPoolItem);
+TYPEINIT1(ScViewObjectModeItem, SfxEnumItem);
+TYPEINIT1(ScDoubleItem, SfxPoolItem);
+TYPEINIT1(ScPageScaleToItem, SfxPoolItem);
+
+//------------------------------------------------------------------------
+
+//
+// allgemeine Hilfsfunktionen
+//
+
+BOOL ScHasPriority( const SvxBorderLine* pThis, const SvxBorderLine* pOther )
+{
+// DBG_ASSERT( pThis || pOther, "LineAttr == 0" );
+
+ if (!pThis)
+ return FALSE;
+ if (!pOther)
+ return TRUE;
+
+ USHORT nThisSize = pThis->GetOutWidth() + pThis->GetDistance() + pThis->GetInWidth();
+ USHORT nOtherSize = pOther->GetOutWidth() + pOther->GetDistance() + pOther->GetInWidth();
+
+ if (nThisSize > nOtherSize)
+ return TRUE;
+ else if (nThisSize < nOtherSize)
+ return FALSE;
+ else
+ {
+ if ( pOther->GetInWidth() && !pThis->GetInWidth() )
+ return TRUE;
+ else if ( pThis->GetInWidth() && !pOther->GetInWidth() )
+ return FALSE;
+ else
+ {
+ return TRUE; //! ???
+ }
+ }
+}
+
+
+//
+// Item - Implementierungen
+//
+
+//------------------------------------------------------------------------
+// Merge
+//------------------------------------------------------------------------
+
+ScMergeAttr::ScMergeAttr():
+ SfxPoolItem(ATTR_MERGE),
+ nColMerge(0),
+ nRowMerge(0)
+{}
+
+//------------------------------------------------------------------------
+
+ScMergeAttr::ScMergeAttr( SCsCOL nCol, SCsROW nRow):
+ SfxPoolItem(ATTR_MERGE),
+ nColMerge(nCol),
+ nRowMerge(nRow)
+{}
+
+//------------------------------------------------------------------------
+
+ScMergeAttr::ScMergeAttr(const ScMergeAttr& rItem):
+ SfxPoolItem(ATTR_MERGE)
+{
+ nColMerge = rItem.nColMerge;
+ nRowMerge = rItem.nRowMerge;
+}
+
+ScMergeAttr::~ScMergeAttr()
+{
+}
+
+//------------------------------------------------------------------------
+
+String ScMergeAttr::GetValueText() const
+{
+ String aString( '(' );
+ aString += String::CreateFromInt32( nColMerge );
+ aString += ',';
+ aString += String::CreateFromInt32( nRowMerge );
+ aString += ')';
+ return aString;
+}
+
+//------------------------------------------------------------------------
+
+int ScMergeAttr::operator==( const SfxPoolItem& rItem ) const
+{
+ DBG_ASSERT( Which() != rItem.Which() || Type() == rItem.Type(), "which ==, type !=" );
+ return (Which() == rItem.Which())
+ && (nColMerge == ((ScMergeAttr&)rItem).nColMerge)
+ && (nRowMerge == ((ScMergeAttr&)rItem).nRowMerge);
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScMergeAttr::Clone( SfxItemPool * ) const
+{
+ return new ScMergeAttr(*this);
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScMergeAttr::Create( SvStream& rStream, USHORT /* nVer */ ) const
+{
+ INT16 nCol;
+ INT16 nRow;
+ rStream >> nCol;
+ rStream >> nRow;
+ return new ScMergeAttr(static_cast<SCCOL>(nCol),static_cast<SCROW>(nRow));
+}
+
+//------------------------------------------------------------------------
+// MergeFlag
+//------------------------------------------------------------------------
+
+ScMergeFlagAttr::ScMergeFlagAttr():
+ SfxInt16Item(ATTR_MERGE_FLAG, 0)
+{
+}
+
+//------------------------------------------------------------------------
+
+ScMergeFlagAttr::ScMergeFlagAttr(INT16 nFlags):
+ SfxInt16Item(ATTR_MERGE_FLAG, nFlags)
+{
+}
+
+ScMergeFlagAttr::~ScMergeFlagAttr()
+{
+}
+
+//------------------------------------------------------------------------
+// Protection
+//------------------------------------------------------------------------
+
+ScProtectionAttr::ScProtectionAttr():
+ SfxPoolItem(ATTR_PROTECTION),
+ bProtection(TRUE),
+ bHideFormula(FALSE),
+ bHideCell(FALSE),
+ bHidePrint(FALSE)
+{
+}
+
+//------------------------------------------------------------------------
+
+ScProtectionAttr::ScProtectionAttr( BOOL bProtect, BOOL bHFormula,
+ BOOL bHCell, BOOL bHPrint):
+ SfxPoolItem(ATTR_PROTECTION),
+ bProtection(bProtect),
+ bHideFormula(bHFormula),
+ bHideCell(bHCell),
+ bHidePrint(bHPrint)
+{
+}
+
+//------------------------------------------------------------------------
+
+ScProtectionAttr::ScProtectionAttr(const ScProtectionAttr& rItem):
+ SfxPoolItem(ATTR_PROTECTION)
+{
+ bProtection = rItem.bProtection;
+ bHideFormula = rItem.bHideFormula;
+ bHideCell = rItem.bHideCell;
+ bHidePrint = rItem.bHidePrint;
+}
+
+ScProtectionAttr::~ScProtectionAttr()
+{
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScProtectionAttr::QueryValue( uno::Any& rVal, BYTE nMemberId ) const
+{
+ nMemberId &= ~CONVERT_TWIPS;
+ switch ( nMemberId )
+ {
+ case 0 :
+ {
+ util::CellProtection aProtection;
+ aProtection.IsLocked = bProtection;
+ aProtection.IsFormulaHidden = bHideFormula;
+ aProtection.IsHidden = bHideCell;
+ aProtection.IsPrintHidden = bHidePrint;
+ rVal <<= aProtection;
+ break;
+ }
+ case MID_1 :
+ rVal <<= (sal_Bool ) bProtection; break;
+ case MID_2 :
+ rVal <<= (sal_Bool ) bHideFormula; break;
+ case MID_3 :
+ rVal <<= (sal_Bool ) bHideCell; break;
+ case MID_4 :
+ rVal <<= (sal_Bool ) bHidePrint; break;
+ default:
+ DBG_ERROR("Wrong MemberID!");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL ScProtectionAttr::PutValue( const uno::Any& rVal, BYTE nMemberId )
+{
+ BOOL bRet = FALSE;
+ sal_Bool bVal = sal_Bool();
+ nMemberId &= ~CONVERT_TWIPS;
+ switch ( nMemberId )
+ {
+ case 0 :
+ {
+ util::CellProtection aProtection;
+ if ( rVal >>= aProtection )
+ {
+ bProtection = aProtection.IsLocked;
+ bHideFormula = aProtection.IsFormulaHidden;
+ bHideCell = aProtection.IsHidden;
+ bHidePrint = aProtection.IsPrintHidden;
+ bRet = TRUE;
+ }
+ else
+ {
+ DBG_ERROR("exception - wrong argument");
+ }
+ break;
+ }
+ case MID_1 :
+ bRet = (rVal >>= bVal); if (bRet) bProtection=bVal; break;
+ case MID_2 :
+ bRet = (rVal >>= bVal); if (bRet) bHideFormula=bVal; break;
+ case MID_3 :
+ bRet = (rVal >>= bVal); if (bRet) bHideCell=bVal; break;
+ case MID_4 :
+ bRet = (rVal >>= bVal); if (bRet) bHidePrint=bVal; break;
+ default:
+ DBG_ERROR("Wrong MemberID!");
+ }
+
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+String ScProtectionAttr::GetValueText() const
+{
+ String aValue;
+ String aStrYes ( ScGlobal::GetRscString(STR_YES) );
+ String aStrNo ( ScGlobal::GetRscString(STR_NO) );
+ sal_Unicode cDelim = ',';
+
+ aValue = '(';
+ aValue += (bProtection ? aStrYes : aStrNo); aValue += cDelim;
+ aValue += (bHideFormula ? aStrYes : aStrNo); aValue += cDelim;
+ aValue += (bHideCell ? aStrYes : aStrNo); aValue += cDelim;
+ aValue += (bHidePrint ? aStrYes : aStrNo);
+ aValue += ')';
+
+ return aValue;
+}
+
+//------------------------------------------------------------------------
+
+SfxItemPresentation ScProtectionAttr::GetPresentation
+ (
+ SfxItemPresentation ePres,
+ SfxMapUnit /* eCoreMetric */,
+ SfxMapUnit /* ePresMetric */,
+ String& rText,
+ const IntlWrapper* /* pIntl */
+ ) const
+{
+ String aStrYes ( ScGlobal::GetRscString(STR_YES) );
+ String aStrNo ( ScGlobal::GetRscString(STR_NO) );
+ String aStrSep = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM( ": " ));
+ String aStrDelim = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM( ", " ));
+
+ switch ( ePres )
+ {
+ case SFX_ITEM_PRESENTATION_NONE:
+ rText.Erase();
+ break;
+
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText = GetValueText();
+ break;
+
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText = ScGlobal::GetRscString(STR_PROTECTION); rText += aStrSep;
+ rText += (bProtection ? aStrYes : aStrNo); rText += aStrDelim;
+ rText += ScGlobal::GetRscString(STR_FORMULAS); rText += aStrSep;
+ rText += (!bHideFormula ? aStrYes : aStrNo); rText += aStrDelim;
+ rText += ScGlobal::GetRscString(STR_HIDE); rText += aStrSep;
+ rText += (bHideCell ? aStrYes : aStrNo); rText += aStrDelim;
+ rText += ScGlobal::GetRscString(STR_PRINT); rText += aStrSep;
+ rText += (!bHidePrint ? aStrYes : aStrNo);
+ break;
+
+ default:
+ ePres = SFX_ITEM_PRESENTATION_NONE;
+ }
+
+ return ePres;
+}
+
+//------------------------------------------------------------------------
+
+int ScProtectionAttr::operator==( const SfxPoolItem& rItem ) const
+{
+ DBG_ASSERT( Which() != rItem.Which() || Type() == rItem.Type(), "which ==, type !=" );
+ return (Which() == rItem.Which())
+ && (bProtection == ((ScProtectionAttr&)rItem).bProtection)
+ && (bHideFormula == ((ScProtectionAttr&)rItem).bHideFormula)
+ && (bHideCell == ((ScProtectionAttr&)rItem).bHideCell)
+ && (bHidePrint == ((ScProtectionAttr&)rItem).bHidePrint);
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScProtectionAttr::Clone( SfxItemPool * ) const
+{
+ return new ScProtectionAttr(*this);
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScProtectionAttr::Create( SvStream& rStream, USHORT /* n */ ) const
+{
+ BOOL bProtect;
+ BOOL bHFormula;
+ BOOL bHCell;
+ BOOL bHPrint;
+
+ rStream >> bProtect;
+ rStream >> bHFormula;
+ rStream >> bHCell;
+ rStream >> bHPrint;
+
+ return new ScProtectionAttr(bProtect,bHFormula,bHCell,bHPrint);
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScProtectionAttr::SetProtection( BOOL bProtect)
+{
+ bProtection = bProtect;
+ return TRUE;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScProtectionAttr::SetHideFormula( BOOL bHFormula)
+{
+ bHideFormula = bHFormula;
+ return TRUE;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScProtectionAttr::SetHideCell( BOOL bHCell)
+{
+ bHideCell = bHCell;
+ return TRUE;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScProtectionAttr::SetHidePrint( BOOL bHPrint)
+{
+ bHidePrint = bHPrint;
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+// ScRangeItem - Tabellenbereich
+// -----------------------------------------------------------------------
+
+int ScRangeItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" );
+
+ return ( aRange == ( (ScRangeItem&)rAttr ).aRange );
+}
+
+// -----------------------------------------------------------------------
+
+SfxPoolItem* ScRangeItem::Clone( SfxItemPool* ) const
+{
+ return new ScRangeItem( *this );
+}
+
+//------------------------------------------------------------------------
+
+SfxItemPresentation ScRangeItem::GetPresentation
+ (
+ SfxItemPresentation ePres,
+ SfxMapUnit /* eCoreUnit */,
+ SfxMapUnit /* ePresUnit */,
+ String& rText,
+ const IntlWrapper* /* pIntl */
+ ) const
+{
+ rText.Erase();
+
+ switch ( ePres )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText = ScGlobal::GetRscString(STR_AREA);
+ rText.AppendAscii(RTL_CONSTASCII_STRINGPARAM( ": " ));
+// break;// Durchfallen !!!
+
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ {
+ String aText;
+ /* Always use OOo:A1 format */
+ aRange.Format( aText );
+ rText += aText;
+ }
+ break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ return ePres;
+}
+
+// -----------------------------------------------------------------------
+// ScTableListItem - Liste von Tabellen(-nummern)
+// -----------------------------------------------------------------------
+
+ScTableListItem::ScTableListItem( const ScTableListItem& rCpy )
+ : SfxPoolItem ( rCpy.Which() ),
+ nCount ( rCpy.nCount )
+{
+ if ( nCount > 0 )
+ {
+ pTabArr = new SCTAB [nCount];
+
+ for ( USHORT i=0; i<nCount; i++ )
+ pTabArr[i] = rCpy.pTabArr[i];
+ }
+ else
+ pTabArr = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+//UNUSED2008-05 ScTableListItem::ScTableListItem( const USHORT nWhichP, const List& rList )
+//UNUSED2008-05 : SfxPoolItem ( nWhichP ),
+//UNUSED2008-05 nCount ( 0 ),
+//UNUSED2008-05 pTabArr ( NULL )
+//UNUSED2008-05 {
+//UNUSED2008-05 SetTableList( rList );
+//UNUSED2008-05 }
+
+// -----------------------------------------------------------------------
+
+ScTableListItem::~ScTableListItem()
+{
+ delete [] pTabArr;
+}
+
+// -----------------------------------------------------------------------
+
+ScTableListItem& ScTableListItem::operator=( const ScTableListItem& rCpy )
+{
+ delete [] pTabArr;
+
+ if ( rCpy.nCount > 0 )
+ {
+ pTabArr = new SCTAB [rCpy.nCount];
+ for ( USHORT i=0; i<rCpy.nCount; i++ )
+ pTabArr[i] = rCpy.pTabArr[i];
+ }
+ else
+ pTabArr = NULL;
+
+ nCount = rCpy.nCount;
+
+ return *this;
+}
+
+// -----------------------------------------------------------------------
+
+int ScTableListItem::operator==( const SfxPoolItem& rAttr ) const
+{
+ DBG_ASSERT( SfxPoolItem::operator==(rAttr), "unequal types" );
+
+ ScTableListItem& rCmp = (ScTableListItem&)rAttr;
+ BOOL bEqual = (nCount == rCmp.nCount);
+
+ if ( nCount > 0 )
+ {
+ USHORT i=0;
+
+ bEqual = ( pTabArr && rCmp.pTabArr );
+
+ while ( bEqual && i<nCount )
+ {
+ bEqual = ( pTabArr[i] == rCmp.pTabArr[i] );
+ i++;
+ }
+ }
+ return bEqual;
+}
+
+// -----------------------------------------------------------------------
+
+SfxPoolItem* ScTableListItem::Clone( SfxItemPool* ) const
+{
+ return new ScTableListItem( *this );
+}
+
+//------------------------------------------------------------------------
+
+SfxItemPresentation ScTableListItem::GetPresentation
+ (
+ SfxItemPresentation ePres,
+ SfxMapUnit /* eCoreUnit */,
+ SfxMapUnit /* ePresUnit */,
+ String& rText,
+ const IntlWrapper* /* pIntl */
+ ) const
+{
+ const sal_Unicode cDelim = ',';
+
+ switch ( ePres )
+ {
+ case SFX_ITEM_PRESENTATION_NONE:
+ rText.Erase();
+ return ePres;
+
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ {
+ rText = '(';
+ if ( nCount>0 && pTabArr )
+ for ( USHORT i=0; i<nCount; i++ )
+ {
+ rText += String::CreateFromInt32( pTabArr[i] );
+ if ( i<(nCount-1) )
+ rText += cDelim;
+ }
+ rText += ')';
+ }
+ return ePres;
+
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText.Erase();
+ return SFX_ITEM_PRESENTATION_NONE;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ return SFX_ITEM_PRESENTATION_NONE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ScTableListItem::GetTableList( List& aList ) const
+{
+ for ( USHORT i=0; i<nCount; i++ )
+ aList.Insert( new SCTAB( pTabArr[i] ) );
+
+ return ( nCount > 0 );
+}
+
+// -----------------------------------------------------------------------
+
+void ScTableListItem::SetTableList( const List& rList )
+{
+ nCount = (USHORT)rList.Count();
+
+ delete [] pTabArr;
+
+ if ( nCount > 0 )
+ {
+ pTabArr = new SCTAB [nCount];
+
+ for ( USHORT i=0; i<nCount; i++ )
+ pTabArr[i] = *( (SCTAB*)rList.GetObject( i ) );
+ }
+ else
+ pTabArr = NULL;
+}
+
+
+// -----------------------------------------------------------------------
+// ScPageHFItem - Daten der Kopf-/Fusszeilen
+// -----------------------------------------------------------------------
+
+ScPageHFItem::ScPageHFItem( USHORT nWhichP )
+ : SfxPoolItem ( nWhichP ),
+ pLeftArea ( NULL ),
+ pCenterArea ( NULL ),
+ pRightArea ( NULL )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScPageHFItem::ScPageHFItem( const ScPageHFItem& rItem )
+ : SfxPoolItem ( rItem ),
+ pLeftArea ( NULL ),
+ pCenterArea ( NULL ),
+ pRightArea ( NULL )
+{
+ if ( rItem.pLeftArea )
+ pLeftArea = rItem.pLeftArea->Clone();
+ if ( rItem.pCenterArea )
+ pCenterArea = rItem.pCenterArea->Clone();
+ if ( rItem.pRightArea )
+ pRightArea = rItem.pRightArea->Clone();
+}
+
+//------------------------------------------------------------------------
+
+ScPageHFItem::~ScPageHFItem()
+{
+ delete pLeftArea;
+ delete pCenterArea;
+ delete pRightArea;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScPageHFItem::QueryValue( uno::Any& rVal, BYTE /* nMemberId */ ) const
+{
+ uno::Reference<sheet::XHeaderFooterContent> xContent =
+ new ScHeaderFooterContentObj( pLeftArea, pCenterArea, pRightArea );
+
+ rVal <<= xContent;
+ return TRUE;
+}
+
+BOOL ScPageHFItem::PutValue( const uno::Any& rVal, BYTE /* nMemberId */ )
+{
+ BOOL bRet = FALSE;
+ uno::Reference<sheet::XHeaderFooterContent> xContent;
+ if ( rVal >>= xContent )
+ {
+ if ( xContent.is() )
+ {
+ ScHeaderFooterContentObj* pImp =
+ ScHeaderFooterContentObj::getImplementation( xContent );
+ if (pImp)
+ {
+ const EditTextObject* pImpLeft = pImp->GetLeftEditObject();
+ delete pLeftArea;
+ pLeftArea = pImpLeft ? pImpLeft->Clone() : NULL;
+
+ const EditTextObject* pImpCenter = pImp->GetCenterEditObject();
+ delete pCenterArea;
+ pCenterArea = pImpCenter ? pImpCenter->Clone() : NULL;
+
+ const EditTextObject* pImpRight = pImp->GetRightEditObject();
+ delete pRightArea;
+ pRightArea = pImpRight ? pImpRight->Clone() : NULL;
+
+ if ( !pLeftArea || !pCenterArea || !pRightArea )
+ {
+ // keine Texte auf NULL stehen lassen
+ ScEditEngineDefaulter aEngine( EditEngine::CreatePool(), TRUE );
+ if (!pLeftArea)
+ pLeftArea = aEngine.CreateTextObject();
+ if (!pCenterArea)
+ pCenterArea = aEngine.CreateTextObject();
+ if (!pRightArea)
+ pRightArea = aEngine.CreateTextObject();
+ }
+
+ bRet = TRUE;
+ }
+ }
+ }
+
+ if (!bRet)
+ {
+ DBG_ERROR("exception - wrong argument");
+ }
+
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+
+String ScPageHFItem::GetValueText() const
+{
+ return String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("ScPageHFItem"));
+}
+
+//------------------------------------------------------------------------
+
+int ScPageHFItem::operator==( const SfxPoolItem& rItem ) const
+{
+ DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal Which or Type" );
+
+ const ScPageHFItem& r = (const ScPageHFItem&)rItem;
+
+ return ScGlobal::EETextObjEqual(pLeftArea, r.pLeftArea)
+ && ScGlobal::EETextObjEqual(pCenterArea, r.pCenterArea)
+ && ScGlobal::EETextObjEqual(pRightArea, r.pRightArea);
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScPageHFItem::Clone( SfxItemPool* ) const
+{
+ return new ScPageHFItem( *this );
+}
+
+//------------------------------------------------------------------------
+
+void lcl_SetSpace( String& rStr, const ESelection& rSel )
+{
+ // Text durch ein Leerzeichen ersetzen, damit Positionen stimmen:
+
+ xub_StrLen nLen = rSel.nEndPos-rSel.nStartPos;
+ rStr.Erase( rSel.nStartPos, nLen-1 );
+ rStr.SetChar( rSel.nStartPos, ' ' );
+}
+
+BOOL lcl_ConvertFields(EditEngine& rEng, const String* pCommands)
+{
+ BOOL bChange = FALSE;
+ USHORT nParCnt = rEng.GetParagraphCount();
+ for (USHORT nPar = 0; nPar<nParCnt; nPar++)
+ {
+ String aStr = rEng.GetText( nPar );
+ xub_StrLen nPos;
+
+ while ((nPos = aStr.Search(pCommands[0])) != STRING_NOTFOUND)
+ {
+ ESelection aSel( nPar,nPos, nPar,nPos+pCommands[0].Len() );
+ rEng.QuickInsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD), aSel );
+ lcl_SetSpace(aStr, aSel ); bChange = TRUE;
+ }
+ while ((nPos = aStr.Search(pCommands[1])) != STRING_NOTFOUND)
+ {
+ ESelection aSel( nPar,nPos, nPar,nPos+pCommands[1].Len() );
+ rEng.QuickInsertField( SvxFieldItem(SvxPagesField(), EE_FEATURE_FIELD), aSel );
+ lcl_SetSpace(aStr, aSel ); bChange = TRUE;
+ }
+ while ((nPos = aStr.Search(pCommands[2])) != STRING_NOTFOUND)
+ {
+ ESelection aSel( nPar,nPos, nPar,nPos+pCommands[2].Len() );
+ rEng.QuickInsertField( SvxFieldItem(SvxDateField(Date(),SVXDATETYPE_VAR), EE_FEATURE_FIELD), aSel );
+ lcl_SetSpace(aStr, aSel ); bChange = TRUE;
+ }
+ while ((nPos = aStr.Search(pCommands[3])) != STRING_NOTFOUND)
+ {
+ ESelection aSel( nPar,nPos, nPar,nPos+pCommands[3].Len() );
+ rEng.QuickInsertField( SvxFieldItem(SvxTimeField(), EE_FEATURE_FIELD ), aSel );
+ lcl_SetSpace(aStr, aSel ); bChange = TRUE;
+ }
+ while ((nPos = aStr.Search(pCommands[4])) != STRING_NOTFOUND)
+ {
+ ESelection aSel( nPar,nPos, nPar,nPos+pCommands[4].Len() );
+ rEng.QuickInsertField( SvxFieldItem(SvxFileField(), EE_FEATURE_FIELD), aSel );
+ lcl_SetSpace(aStr, aSel ); bChange = TRUE;
+ }
+ while ((nPos = aStr.Search(pCommands[5])) != STRING_NOTFOUND)
+ {
+ ESelection aSel( nPar,nPos, nPar,nPos+pCommands[5].Len() );
+ rEng.QuickInsertField( SvxFieldItem(SvxTableField(), EE_FEATURE_FIELD), aSel );
+ lcl_SetSpace(aStr, aSel ); bChange = TRUE;
+ }
+ }
+ return bChange;
+}
+
+#define SC_FIELD_COUNT 6
+
+SfxPoolItem* ScPageHFItem::Create( SvStream& rStream, USHORT nVer ) const
+{
+ EditTextObject* pLeft = EditTextObject::Create(rStream);
+ EditTextObject* pCenter = EditTextObject::Create(rStream);
+ EditTextObject* pRight = EditTextObject::Create(rStream);
+
+ DBG_ASSERT( pLeft && pCenter && pRight, "Error reading ScPageHFItem" );
+
+ if ( pLeft == NULL || pLeft->GetParagraphCount() == 0 ||
+ pCenter == NULL || pCenter->GetParagraphCount() == 0 ||
+ pRight == NULL || pRight->GetParagraphCount() == 0 )
+ {
+ // If successfully loaded, each object contains at least one paragraph.
+ // Excel import in 5.1 created broken TextObjects (#67442#) that are
+ // corrected here to avoid saving wrong files again (#90487#).
+
+ ScEditEngineDefaulter aEngine( EditEngine::CreatePool(), TRUE );
+ if ( pLeft == NULL || pLeft->GetParagraphCount() == 0 )
+ {
+ delete pLeft;
+ pLeft = aEngine.CreateTextObject();
+ }
+ if ( pCenter == NULL || pCenter->GetParagraphCount() == 0 )
+ {
+ delete pCenter;
+ pCenter = aEngine.CreateTextObject();
+ }
+ if ( pRight == NULL || pRight->GetParagraphCount() == 0 )
+ {
+ delete pRight;
+ pRight = aEngine.CreateTextObject();
+ }
+ }
+
+ if ( nVer < 1 ) // alte Feldbefehle umsetzen
+ {
+ USHORT i;
+ const String& rDel = ScGlobal::GetRscString( STR_HFCMD_DELIMITER );
+ String aCommands[SC_FIELD_COUNT];
+ for (i=0; i<SC_FIELD_COUNT; i++)
+ aCommands[i] = rDel;
+ aCommands[0] += ScGlobal::GetRscString(STR_HFCMD_PAGE);
+ aCommands[1] += ScGlobal::GetRscString(STR_HFCMD_PAGES);
+ aCommands[2] += ScGlobal::GetRscString(STR_HFCMD_DATE);
+ aCommands[3] += ScGlobal::GetRscString(STR_HFCMD_TIME);
+ aCommands[4] += ScGlobal::GetRscString(STR_HFCMD_FILE);
+ aCommands[5] += ScGlobal::GetRscString(STR_HFCMD_TABLE);
+ for (i=0; i<SC_FIELD_COUNT; i++)
+ aCommands[i] += rDel;
+
+ ScEditEngineDefaulter aEngine( EditEngine::CreatePool(), TRUE );
+ aEngine.SetText(*pLeft);
+ if (lcl_ConvertFields(aEngine,aCommands))
+ {
+ delete pLeft;
+ pLeft = aEngine.CreateTextObject();
+ }
+ aEngine.SetText(*pCenter);
+ if (lcl_ConvertFields(aEngine,aCommands))
+ {
+ delete pCenter;
+ pCenter = aEngine.CreateTextObject();
+ }
+ aEngine.SetText(*pRight);
+ if (lcl_ConvertFields(aEngine,aCommands))
+ {
+ delete pRight;
+ pRight = aEngine.CreateTextObject();
+ }
+ }
+ else if ( nVer < 2 )
+ { // nichts tun, SvxFileField nicht gegen SvxExtFileField austauschen
+ }
+
+ ScPageHFItem* pItem = new ScPageHFItem( Which() );
+ pItem->SetArea( pLeft, SC_HF_LEFTAREA );
+ pItem->SetArea( pCenter, SC_HF_CENTERAREA );
+ pItem->SetArea( pRight, SC_HF_RIGHTAREA );
+
+ return pItem;
+}
+
+//------------------------------------------------------------------------
+
+class ScFieldChangerEditEngine : public ScEditEngineDefaulter
+{
+ TypeId aExtFileId;
+ USHORT nConvPara;
+ xub_StrLen nConvPos;
+ BOOL bConvert;
+
+public:
+ ScFieldChangerEditEngine( SfxItemPool* pEnginePool, BOOL bDeleteEnginePool );
+ virtual ~ScFieldChangerEditEngine() {}
+
+ virtual String CalcFieldValue( const SvxFieldItem& rField, USHORT nPara,
+ USHORT nPos, Color*& rTxtColor,
+ Color*& rFldColor );
+
+//UNUSED2008-05 BOOL ConvertFields();
+};
+
+ScFieldChangerEditEngine::ScFieldChangerEditEngine( SfxItemPool* pEnginePoolP,
+ BOOL bDeleteEnginePoolP ) :
+ ScEditEngineDefaulter( pEnginePoolP, bDeleteEnginePoolP ),
+ aExtFileId( TYPE( SvxExtFileField ) ),
+ nConvPara( 0 ),
+ nConvPos( 0 ),
+ bConvert( FALSE )
+{
+}
+
+String ScFieldChangerEditEngine::CalcFieldValue( const SvxFieldItem& rField,
+ USHORT nPara, USHORT nPos, Color*& /* rTxtColor */, Color*& /* rFldColor */ )
+{
+ const SvxFieldData* pFieldData = rField.GetField();
+ if ( pFieldData && pFieldData->Type() == aExtFileId )
+ {
+ bConvert = TRUE;
+ nConvPara = nPara;
+ nConvPos = nPos;
+ }
+ return EMPTY_STRING;
+}
+
+//UNUSED2008-05 BOOL ScFieldChangerEditEngine::ConvertFields()
+//UNUSED2008-05 {
+//UNUSED2008-05 BOOL bConverted = FALSE;
+//UNUSED2008-05 do
+//UNUSED2008-05 {
+//UNUSED2008-05 bConvert = FALSE;
+//UNUSED2008-05 UpdateFields();
+//UNUSED2008-05 if ( bConvert )
+//UNUSED2008-05 {
+//UNUSED2008-05 ESelection aSel( nConvPara, nConvPos, nConvPara, nConvPos+1 );
+//UNUSED2008-05 QuickInsertField( SvxFieldItem( SvxFileField(), EE_FEATURE_FIELD), aSel );
+//UNUSED2008-05 bConverted = TRUE;
+//UNUSED2008-05 }
+//UNUSED2008-05 } while ( bConvert );
+//UNUSED2008-05 return bConverted;
+//UNUSED2008-05 }
+
+void ScPageHFItem::SetLeftArea( const EditTextObject& rNew )
+{
+ delete pLeftArea;
+ pLeftArea = rNew.Clone();
+}
+
+//------------------------------------------------------------------------
+
+void ScPageHFItem::SetCenterArea( const EditTextObject& rNew )
+{
+ delete pCenterArea;
+ pCenterArea = rNew.Clone();
+}
+
+//------------------------------------------------------------------------
+
+void ScPageHFItem::SetRightArea( const EditTextObject& rNew )
+{
+ delete pRightArea;
+ pRightArea = rNew.Clone();
+}
+
+void ScPageHFItem::SetArea( EditTextObject *pNew, int nArea )
+{
+ switch ( nArea )
+ {
+ case SC_HF_LEFTAREA: delete pLeftArea; pLeftArea = pNew; break;
+ case SC_HF_CENTERAREA: delete pCenterArea; pCenterArea = pNew; break;
+ case SC_HF_RIGHTAREA: delete pRightArea; pRightArea = pNew; break;
+ default:
+ DBG_ERROR( "New Area?" );
+ }
+}
+
+//-----------------------------------------------------------------------
+// ScViewObjectModeItem - Darstellungsmodus von ViewObjekten
+//-----------------------------------------------------------------------
+
+ScViewObjectModeItem::ScViewObjectModeItem( USHORT nWhichP )
+ : SfxEnumItem( nWhichP, VOBJ_MODE_SHOW )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScViewObjectModeItem::ScViewObjectModeItem( USHORT nWhichP, ScVObjMode eMode )
+ : SfxEnumItem( nWhichP, sal::static_int_cast<USHORT>(eMode) )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScViewObjectModeItem::~ScViewObjectModeItem()
+{
+}
+
+//------------------------------------------------------------------------
+
+SfxItemPresentation ScViewObjectModeItem::GetPresentation
+(
+ SfxItemPresentation ePres,
+ SfxMapUnit /* eCoreUnit */,
+ SfxMapUnit /* ePresUnit */,
+ String& rText,
+ const IntlWrapper* /* pIntl */
+) const
+{
+ String aDel = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM(": "));
+ rText.Erase();
+
+ switch ( ePres )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ switch( Which() )
+ {
+ case SID_SCATTR_PAGE_CHARTS:
+ rText = ScGlobal::GetRscString(STR_VOBJ_CHART);
+ rText += aDel;
+ break;
+
+ case SID_SCATTR_PAGE_OBJECTS:
+ rText = ScGlobal::GetRscString(STR_VOBJ_OBJECT);
+ rText += aDel;
+ break;
+
+ case SID_SCATTR_PAGE_DRAWINGS:
+ rText = ScGlobal::GetRscString(STR_VOBJ_DRAWINGS);
+ rText += aDel;
+ break;
+
+ default:
+ ePres = SFX_ITEM_PRESENTATION_NAMELESS;//das geht immer!
+ break;
+ }
+// break; // DURCHFALLEN!!!
+
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText += ScGlobal::GetRscString(STR_VOBJ_MODE_SHOW+GetValue());
+ break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ return ePres;
+}
+
+//------------------------------------------------------------------------
+
+String ScViewObjectModeItem::GetValueText( USHORT nVal ) const
+{
+ DBG_ASSERT( nVal <= VOBJ_MODE_HIDE, "enum overflow!" );
+
+ return ScGlobal::GetRscString( STR_VOBJ_MODE_SHOW + (nVal % 2));
+}
+
+//------------------------------------------------------------------------
+
+USHORT ScViewObjectModeItem::GetValueCount() const
+{
+ return 2;
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScViewObjectModeItem::Clone( SfxItemPool* ) const
+{
+ return new ScViewObjectModeItem( *this );
+}
+
+//------------------------------------------------------------------------
+
+USHORT ScViewObjectModeItem::GetVersion( USHORT /* nFileVersion */ ) const
+{
+ return 1;
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScViewObjectModeItem::Create(
+ SvStream& rStream,
+ USHORT nVersion ) const
+{
+ if ( nVersion == 0 )
+ {
+ // alte Version mit AllEnumItem -> mit Mode "Show" erzeugen
+ return new ScViewObjectModeItem( Which() );
+ }
+ else
+ {
+ USHORT nVal;
+ rStream >> nVal;
+
+ //#i80528# adapt to new range eventually
+ if((USHORT)VOBJ_MODE_HIDE < nVal) nVal = (USHORT)VOBJ_MODE_SHOW;
+
+ return new ScViewObjectModeItem( Which(), (ScVObjMode)nVal);
+ }
+}
+
+// -----------------------------------------------------------------------
+// double
+// -----------------------------------------------------------------------
+
+ScDoubleItem::ScDoubleItem( USHORT nWhichP, double nVal )
+ : SfxPoolItem ( nWhichP ),
+ nValue ( nVal )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScDoubleItem::ScDoubleItem( const ScDoubleItem& rItem )
+ : SfxPoolItem ( rItem )
+{
+ nValue = rItem.nValue;
+}
+
+//------------------------------------------------------------------------
+
+String ScDoubleItem::GetValueText() const
+{
+ return String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("ScDoubleItem"));
+}
+
+//------------------------------------------------------------------------
+
+int ScDoubleItem::operator==( const SfxPoolItem& rItem ) const
+{
+ DBG_ASSERT( SfxPoolItem::operator==( rItem ), "unequal Which or Type" );
+ const ScDoubleItem& _rItem = (const ScDoubleItem&)rItem;
+ return int(nValue == _rItem.nValue);
+ //int(nValue == ((const ScDoubleItem&)rItem).nValue);
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScDoubleItem::Clone( SfxItemPool* ) const
+{
+ return new ScDoubleItem( *this );
+}
+
+//------------------------------------------------------------------------
+
+SfxPoolItem* ScDoubleItem::Create( SvStream& rStream, USHORT /* nVer */ ) const
+{
+ double nTmp=0;
+ rStream >> nTmp;
+
+ ScDoubleItem* pItem = new ScDoubleItem( Which(), nTmp );
+
+ return pItem;
+}
+
+//------------------------------------------------------------------------
+
+ScDoubleItem::~ScDoubleItem()
+{
+}
+
+
+// ============================================================================
+
+ScPageScaleToItem::ScPageScaleToItem() :
+ SfxPoolItem( ATTR_PAGE_SCALETO ),
+ mnWidth( 0 ),
+ mnHeight( 0 )
+{
+}
+
+ScPageScaleToItem::ScPageScaleToItem( sal_uInt16 nWidth, sal_uInt16 nHeight ) :
+ SfxPoolItem( ATTR_PAGE_SCALETO ),
+ mnWidth( nWidth ),
+ mnHeight( nHeight )
+{
+}
+
+ScPageScaleToItem::~ScPageScaleToItem()
+{
+}
+
+ScPageScaleToItem* ScPageScaleToItem::Clone( SfxItemPool* ) const
+{
+ return new ScPageScaleToItem( *this );
+}
+
+int ScPageScaleToItem::operator==( const SfxPoolItem& rCmp ) const
+{
+ DBG_ASSERT( SfxPoolItem::operator==( rCmp ), "ScPageScaleToItem::operator== - unequal wid or type" );
+ const ScPageScaleToItem& rPageCmp = static_cast< const ScPageScaleToItem& >( rCmp );
+ return ((mnWidth == rPageCmp.mnWidth) && (mnHeight == rPageCmp.mnHeight)) ? 1 : 0;
+}
+
+namespace {
+void lclAppendScalePageCount( String& rText, sal_uInt16 nPages )
+{
+ rText.AppendAscii( ": " );
+ if( nPages )
+ {
+ String aPages( ScGlobal::GetRscString( STR_SCATTR_PAGE_SCALE_PAGES ) );
+ aPages.SearchAndReplaceAscii( "%1", String::CreateFromInt32( nPages ) );
+ rText.Append( aPages );
+ }
+ else
+ rText.Append( ScGlobal::GetRscString( STR_SCATTR_PAGE_SCALE_AUTO ) );
+}
+} // namespace
+
+SfxItemPresentation ScPageScaleToItem::GetPresentation(
+ SfxItemPresentation ePres, SfxMapUnit, SfxMapUnit, XubString& rText, const IntlWrapper* ) const
+{
+ rText.Erase();
+ if( !IsValid() || (ePres == SFX_ITEM_PRESENTATION_NONE) )
+ return SFX_ITEM_PRESENTATION_NONE;
+
+ String aName( ScGlobal::GetRscString( STR_SCATTR_PAGE_SCALETO ) );
+ String aValue( ScGlobal::GetRscString( STR_SCATTR_PAGE_SCALE_WIDTH ) );
+ lclAppendScalePageCount( aValue, mnWidth );
+ aValue.AppendAscii( ", " ).Append( ScGlobal::GetRscString( STR_SCATTR_PAGE_SCALE_HEIGHT ) );
+ lclAppendScalePageCount( aValue, mnHeight );
+
+ switch( ePres )
+ {
+ case SFX_ITEM_PRESENTATION_NONE:
+ break;
+
+ case SFX_ITEM_PRESENTATION_NAMEONLY:
+ rText = aName;
+ break;
+
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText = aValue;
+ break;
+
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText.Assign( aName ).AppendAscii( " (" ).Append( aValue ).Append( ')' );
+ break;
+
+ default:
+ DBG_ERRORFILE( "ScPageScaleToItem::GetPresentation - unknown presentation mode" );
+ ePres = SFX_ITEM_PRESENTATION_NONE;
+ }
+ return ePres;
+}
+
+BOOL ScPageScaleToItem::QueryValue( uno::Any& rAny, BYTE nMemberId ) const
+{
+ BOOL bRet = TRUE;
+ switch( nMemberId )
+ {
+ case SC_MID_PAGE_SCALETO_WIDTH: rAny <<= mnWidth; break;
+ case SC_MID_PAGE_SCALETO_HEIGHT: rAny <<= mnHeight; break;
+ default:
+ DBG_ERRORFILE( "ScPageScaleToItem::QueryValue - unknown member ID" );
+ bRet = FALSE;
+ }
+ return bRet;
+}
+
+BOOL ScPageScaleToItem::PutValue( const uno::Any& rAny, BYTE nMemberId )
+{
+ BOOL bRet = FALSE;
+ switch( nMemberId )
+ {
+ case SC_MID_PAGE_SCALETO_WIDTH: bRet = rAny >>= mnWidth; break;
+ case SC_MID_PAGE_SCALETO_HEIGHT: bRet = rAny >>= mnHeight; break;
+ default:
+ DBG_ERRORFILE( "ScPageScaleToItem::PutValue - unknown member ID" );
+ }
+ return bRet;
+}
+
+// ============================================================================
+
+
diff --git a/sc/source/core/data/autonamecache.cxx b/sc/source/core/data/autonamecache.cxx
new file mode 100644
index 000000000000..d106e5824571
--- /dev/null
+++ b/sc/source/core/data/autonamecache.cxx
@@ -0,0 +1,111 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: autonamecache.cxx,v $
+ * $Revision: 1.4.128.1 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <unotools/transliterationwrapper.hxx>
+
+#include "autonamecache.hxx"
+#include "dociter.hxx"
+#include "cell.hxx"
+
+// -----------------------------------------------------------------------
+
+ScAutoNameCache::ScAutoNameCache( ScDocument* pD ) :
+ pDoc( pD ),
+ nCurrentTab( 0 ) // doesn't matter - aNames is empty
+{
+}
+
+ScAutoNameCache::~ScAutoNameCache()
+{
+}
+
+const ScAutoNameAddresses& ScAutoNameCache::GetNameOccurences( const String& rName, SCTAB nTab )
+{
+ if ( nTab != nCurrentTab )
+ {
+ // the lists are valid only for one sheet, so they are cleared when another sheet is used
+ aNames.clear();
+ nCurrentTab = nTab;
+ }
+
+ ScAutoNameHashMap::const_iterator aFound = aNames.find( rName );
+ if ( aFound != aNames.end() )
+ return aFound->second; // already initialized
+
+ ScAutoNameAddresses& rAddresses = aNames[rName];
+
+ ScCellIterator aIter( pDoc, ScRange( 0, 0, nCurrentTab, MAXCOL, MAXROW, nCurrentTab ) );
+ for ( ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext() )
+ {
+ // don't check code length here, always use the stored result
+ // (AutoCalc is disabled during CompileXML)
+
+ if ( pCell->HasStringData() )
+ {
+ String aStr;
+ CellType eType = pCell->GetCellType();
+ switch ( eType )
+ {
+ case CELLTYPE_STRING:
+ ((ScStringCell*)pCell)->GetString( aStr );
+ break;
+ case CELLTYPE_FORMULA:
+ ((ScFormulaCell*)pCell)->GetString( aStr );
+ break;
+ case CELLTYPE_EDIT:
+ ((ScEditCell*)pCell)->GetString( aStr );
+ break;
+ case CELLTYPE_NONE:
+ case CELLTYPE_VALUE:
+ case CELLTYPE_NOTE:
+ case CELLTYPE_SYMBOLS:
+#ifdef DBG_UTIL
+ case CELLTYPE_DESTROYED:
+#endif
+ ; // nothing, prevent compiler warning
+ break;
+ }
+ if ( ScGlobal::pTransliteration->isEqual( aStr, rName ) )
+ {
+ rAddresses.push_back( ScAddress( aIter.GetCol(), aIter.GetRow(), aIter.GetTab() ) );
+ }
+ }
+ }
+
+ return rAddresses;
+}
+
diff --git a/sc/source/core/data/bcaslot.cxx b/sc/source/core/data/bcaslot.cxx
new file mode 100644
index 000000000000..34b19662debf
--- /dev/null
+++ b/sc/source/core/data/bcaslot.cxx
@@ -0,0 +1,720 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: bcaslot.cxx,v $
+ * $Revision: 1.11 $
+ *
+ * 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 <sfx2/objsh.hxx>
+#include <svtools/listener.hxx>
+
+#include "document.hxx"
+#include "brdcst.hxx"
+#include "bcaslot.hxx"
+#include "scerrors.hxx"
+#include "docoptio.hxx"
+#include "refupdat.hxx"
+#include "table.hxx"
+
+// Number of slots per dimension
+// must be integer divisors of MAXCOLCOUNT respectively MAXROWCOUNT
+#define BCA_SLOTS_COL ((MAXCOLCOUNT_DEFINE) / 16)
+#if MAXROWCOUNT_DEFINE == 32000
+#define BCA_SLOTS_ROW 256
+#else
+#define BCA_SLOTS_ROW ((MAXROWCOUNT_DEFINE) / 128)
+#endif
+#define BCA_SLOT_COLS ((MAXCOLCOUNT_DEFINE) / BCA_SLOTS_COL)
+#define BCA_SLOT_ROWS ((MAXROWCOUNT_DEFINE) / BCA_SLOTS_ROW)
+// multiple?
+#if (BCA_SLOT_COLS * BCA_SLOTS_COL) != (MAXCOLCOUNT_DEFINE)
+#error bad BCA_SLOTS_COL value!
+#endif
+#if (BCA_SLOT_ROWS * BCA_SLOTS_ROW) != (MAXROWCOUNT_DEFINE)
+#error bad BCA_SLOTS_ROW value!
+#endif
+// size of slot array
+#define BCA_SLOTS_DEFINE (BCA_SLOTS_COL * BCA_SLOTS_ROW)
+// Arbitrary 2**31/8, assuming size_t can hold at least 2^31 values and
+// sizeof_ptr is at most 8 bytes. You'd probably doom your machine's memory
+// anyway, once you reached these values..
+#if BCA_SLOTS_DEFINE > 268435456
+#error BCA_SLOTS_DEFINE DOOMed!
+#endif
+// type safe constant
+const SCSIZE BCA_SLOTS = BCA_SLOTS_DEFINE;
+
+// STATIC DATA -----------------------------------------------------------
+
+TYPEINIT1( ScHint, SfxSimpleHint );
+TYPEINIT1( ScAreaChangedHint, SfxHint );
+
+
+ScBroadcastAreaSlot::ScBroadcastAreaSlot( ScDocument* pDocument,
+ ScBroadcastAreaSlotMachine* pBASMa ) :
+ aTmpSeekBroadcastArea( ScRange()),
+ pDoc( pDocument ),
+ pBASM( pBASMa )
+{
+}
+
+
+ScBroadcastAreaSlot::~ScBroadcastAreaSlot()
+{
+ for ( ScBroadcastAreas::iterator aIter = aBroadcastAreaTbl.begin();
+ aIter != aBroadcastAreaTbl.end(); ++aIter)
+ {
+ if (!(*aIter)->DecRef())
+ delete *aIter;
+ }
+}
+
+
+// Only here new ScBroadcastArea objects are created, prevention of dupes.
+// If rpArea != NULL then no listeners are startet, only the area is inserted
+// and the reference count increased.
+void ScBroadcastAreaSlot::StartListeningArea( const ScRange& rRange,
+ SvtListener* pListener, ScBroadcastArea*& rpArea
+ )
+{
+ DBG_ASSERT(pListener, "StartListeningArea: pListener Null");
+ if ( pDoc->GetHardRecalcState() )
+ return;
+ if (aBroadcastAreaTbl.size() >= aBroadcastAreaTbl.max_size())
+ { // this is more hypothetical now, check existed for old SV_PTRARR_SORT
+ if ( !pDoc->GetHardRecalcState() )
+ {
+ pDoc->SetHardRecalcState( 1 );
+
+ SfxObjectShell* pShell = pDoc->GetDocumentShell();
+ DBG_ASSERT( pShell, "Missing DocShell :-/" );
+
+ if ( pShell )
+ pShell->SetError( SCWARN_CORE_HARD_RECALC );
+
+ pDoc->SetAutoCalc( FALSE );
+ pDoc->SetHardRecalcState( 2 );
+ }
+ return;
+ }
+ if ( !rpArea )
+ {
+ rpArea = new ScBroadcastArea( rRange );
+ // Most times the area doesn't exist yet, immediately trying to insert
+ // it saves an attempt to find it.
+ if (aBroadcastAreaTbl.insert( rpArea).second)
+ rpArea->IncRef();
+ else
+ {
+ delete rpArea;
+ ScBroadcastAreas::const_iterator aIter( FindBroadcastArea( rRange));
+ if (aIter != aBroadcastAreaTbl.end())
+ rpArea = *aIter;
+ else
+ {
+ DBG_ERRORFILE("BroadcastArea not inserted and not found?!?");
+ rpArea = 0;
+ }
+ }
+ if (rpArea)
+ pListener->StartListening( rpArea->GetBroadcaster() );
+ }
+ else
+ {
+ aBroadcastAreaTbl.insert( rpArea );
+ rpArea->IncRef();
+ }
+}
+
+
+// If rpArea != NULL then no listeners are stopped, only the area is removed
+// and the reference count decreased.
+void ScBroadcastAreaSlot::EndListeningArea( const ScRange& rRange,
+ SvtListener* pListener, ScBroadcastArea*& rpArea
+ )
+{
+ DBG_ASSERT(pListener, "EndListeningArea: pListener Null");
+ if ( !rpArea )
+ {
+ ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange));
+ if (aIter == aBroadcastAreaTbl.end())
+ return;
+ rpArea = *aIter;
+ pListener->EndListening( rpArea->GetBroadcaster() );
+ if ( !rpArea->GetBroadcaster().HasListeners() )
+ { // if nobody is listening we can dispose it
+ aBroadcastAreaTbl.erase( aIter);
+ if ( !rpArea->DecRef() )
+ {
+ delete rpArea;
+ rpArea = NULL;
+ }
+ }
+ }
+ else
+ {
+ if ( !rpArea->GetBroadcaster().HasListeners() )
+ {
+ ScBroadcastAreas::iterator aIter( FindBroadcastArea( rRange));
+ if (aIter == aBroadcastAreaTbl.end())
+ return;
+ aBroadcastAreaTbl.erase( aIter);
+ if ( !rpArea->DecRef() )
+ {
+ delete rpArea;
+ rpArea = NULL;
+ }
+ }
+ }
+}
+
+
+ScBroadcastAreas::iterator ScBroadcastAreaSlot::FindBroadcastArea(
+ const ScRange& rRange ) const
+{
+ aTmpSeekBroadcastArea.UpdateRange( rRange);
+ return aBroadcastAreaTbl.find( &aTmpSeekBroadcastArea);
+}
+
+
+BOOL ScBroadcastAreaSlot::AreaBroadcast( const ScHint& rHint) const
+{
+ if (aBroadcastAreaTbl.empty())
+ return FALSE;
+ BOOL bIsBroadcasted = FALSE;
+ const ScAddress& rAddress = rHint.GetAddress();
+ // Unfortunately we can't search for the first matching entry.
+ ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
+ while (aIter != aBroadcastAreaTbl.end())
+ {
+ ScBroadcastArea* pArea = *aIter;
+ // A Notify() during broadcast may call EndListeningArea() and thus
+ // dispose this area if it was the last listener, which would
+ // invalidate the iterator, hence increment before call.
+ ++aIter;
+ const ScRange& rAreaRange = pArea->GetRange();
+ if (rAreaRange.In( rAddress))
+ {
+ if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
+ {
+ pArea->GetBroadcaster().Broadcast( rHint);
+ bIsBroadcasted = TRUE;
+ }
+ }
+ else if (rAddress < rAreaRange.aStart)
+ break; // while loop, only ranges greater than rAddress follow
+ }
+ return bIsBroadcasted;
+}
+
+
+BOOL ScBroadcastAreaSlot::AreaBroadcastInRange( const ScRange& rRange,
+ const ScHint& rHint) const
+{
+ if (aBroadcastAreaTbl.empty())
+ return FALSE;
+ BOOL bIsBroadcasted = FALSE;
+ // Unfortunately we can't search for the first matching entry.
+ ScBroadcastAreas::const_iterator aIter( aBroadcastAreaTbl.begin());
+ while (aIter != aBroadcastAreaTbl.end())
+ {
+ ScBroadcastArea* pArea = *aIter;
+ // A Notify() during broadcast may call EndListeningArea() and thus
+ // dispose this area if it was the last listener, which would
+ // invalidate the iterator, hence increment before call.
+ ++aIter;
+ const ScRange& rAreaRange = pArea->GetRange();
+ if (rAreaRange.Intersects( rRange ))
+ {
+ if (!pBASM->IsInBulkBroadcast() || pBASM->InsertBulkArea( pArea))
+ {
+ pArea->GetBroadcaster().Broadcast( rHint);
+ bIsBroadcasted = TRUE;
+ }
+ }
+ else if (rRange.aEnd < rAreaRange.aStart)
+ break; // while loop, only ranges greater than end address follow
+ }
+ return bIsBroadcasted;
+}
+
+
+void ScBroadcastAreaSlot::DelBroadcastAreasInRange( const ScRange& rRange )
+{
+ if (aBroadcastAreaTbl.empty())
+ return;
+ // Searching for areas bound completely within rRange, so it's fine to
+ // exclude all upper left corners smaller than the upper left corner of
+ // rRange and get a lower bound.
+ aTmpSeekBroadcastArea.UpdateRange( ScRange( rRange.aStart));
+ // Search for lower bound, inclusive, not less than.
+ ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.lower_bound(
+ &aTmpSeekBroadcastArea));
+ for ( ; aIter != aBroadcastAreaTbl.end(); )
+ {
+ const ScRange& rAreaRange = (*aIter)->GetRange();
+ if (rRange.In( rAreaRange))
+ {
+ ScBroadcastArea* pArea = *aIter;
+ if (!pArea->DecRef())
+ {
+ if (pBASM->IsInBulkBroadcast())
+ pBASM->RemoveBulkArea( pArea);
+ delete pArea;
+ }
+ ScBroadcastAreas::iterator aDel( aIter);
+ ++aIter;
+ aBroadcastAreaTbl.erase( aDel);
+ }
+ else if (rRange.aEnd < rAreaRange.aStart)
+ break; // for loop, only ranges greater than end address follow
+ else
+ ++aIter;
+ }
+}
+
+
+void ScBroadcastAreaSlot::UpdateRemove( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz
+ )
+{
+ if (aBroadcastAreaTbl.empty())
+ return;
+
+ SCCOL nCol1, nCol2, theCol1, theCol2;
+ SCROW nRow1, nRow2, theRow1, theRow2;
+ SCTAB nTab1, nTab2, theTab1, theTab2;
+ nCol1 = rRange.aStart.Col();
+ nRow1 = rRange.aStart.Row();
+ nTab1 = rRange.aStart.Tab();
+ nCol2 = rRange.aEnd.Col();
+ nRow2 = rRange.aEnd.Row();
+ nTab2 = rRange.aEnd.Tab();
+ for ( ScBroadcastAreas::iterator aIter( aBroadcastAreaTbl.begin());
+ aIter != aBroadcastAreaTbl.end(); )
+ {
+ ScBroadcastArea* pArea = *aIter;
+ ScBroadcastAreas::iterator aDel( aIter);
+ ++aIter;
+ if ( pArea->IsInUpdateChain() )
+ {
+ aBroadcastAreaTbl.erase( aDel);
+ pArea->DecRef();
+ }
+ else
+ {
+ const ScAddress& rAdr1 = pArea->GetStart();
+ theCol1 = rAdr1.Col();
+ theRow1 = rAdr1.Row();
+ theTab1 = rAdr1.Tab();
+ const ScAddress& rAdr2 = pArea->GetEnd();
+ theCol2 = rAdr2.Col();
+ theRow2 = rAdr2.Row();
+ theTab2 = rAdr2.Tab();
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
+ theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 )
+ )
+ {
+ aBroadcastAreaTbl.erase( aDel);
+ pArea->DecRef();
+ if (pBASM->IsInBulkBroadcast())
+ pBASM->RemoveBulkArea( pArea);
+ pArea->SetInUpdateChain( TRUE );
+ ScBroadcastArea* pUC = pBASM->GetEOUpdateChain();
+ if ( pUC )
+ pUC->SetUpdateChainNext( pArea );
+ else // no tail => no head
+ pBASM->SetUpdateChain( pArea );
+ pBASM->SetEOUpdateChain( pArea );
+ }
+ }
+ }
+}
+
+
+void ScBroadcastAreaSlot::UpdateInsert( ScBroadcastArea* pArea )
+{
+ aBroadcastAreaTbl.insert( pArea );
+ pArea->IncRef();
+}
+
+
+// --- ScBroadcastAreaSlotMachine -------------------------------------
+
+ScBroadcastAreaSlotMachine::ScBroadcastAreaSlotMachine(
+ ScDocument* pDocument ) :
+ pBCAlways( NULL ),
+ pDoc( pDocument ),
+ pUpdateChain( NULL ),
+ pEOUpdateChain( NULL ),
+ nInBulkBroadcast( 0 )
+{
+ ppSlots = new ScBroadcastAreaSlot* [ BCA_SLOTS ];
+ memset( ppSlots, 0 , sizeof( ScBroadcastAreaSlot* ) * BCA_SLOTS );
+}
+
+
+ScBroadcastAreaSlotMachine::~ScBroadcastAreaSlotMachine()
+{
+ for ( ScBroadcastAreaSlot** pp = ppSlots + BCA_SLOTS; --pp >= ppSlots; )
+ {
+ if ( *pp )
+ delete *pp;
+ }
+ delete[] ppSlots;
+
+ delete pBCAlways;
+}
+
+
+inline SCSIZE ScBroadcastAreaSlotMachine::ComputeSlotOffset(
+ const ScAddress& rAddress ) const
+{
+ SCROW nRow = rAddress.Row();
+ SCCOL nCol = rAddress.Col();
+ if ( !ValidRow(nRow) || !ValidCol(nCol) )
+ {
+ DBG_ASSERT( FALSE, "Row/Col ungueltig!" );
+ return 0;
+ }
+ else
+ return
+ static_cast<SCSIZE>(nRow) / BCA_SLOT_ROWS +
+ static_cast<SCSIZE>(nCol) / BCA_SLOT_COLS * BCA_SLOTS_ROW;
+}
+
+
+void ScBroadcastAreaSlotMachine::ComputeAreaPoints( const ScRange& rRange,
+ SCSIZE& rStart, SCSIZE& rEnd, SCSIZE& rRowBreak
+ ) const
+{
+ rStart = ComputeSlotOffset( rRange.aStart );
+ rEnd = ComputeSlotOffset( rRange.aEnd );
+ // count of row slots per column minus one
+ rRowBreak = ComputeSlotOffset(
+ ScAddress( rRange.aStart.Col(), rRange.aEnd.Row(), 0 ) ) - rStart;
+}
+
+
+void ScBroadcastAreaSlotMachine::StartListeningArea( const ScRange& rRange,
+ SvtListener* pListener
+ )
+{
+ if ( rRange == BCA_LISTEN_ALWAYS )
+ {
+ if ( !pBCAlways )
+ pBCAlways = new SvtBroadcaster;
+ pListener->StartListening( *pBCAlways );
+ }
+ else
+ {
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ ScBroadcastArea* pArea = NULL;
+ while ( nOff <= nEnd )
+ {
+ if ( !*pp )
+ *pp = new ScBroadcastAreaSlot( pDoc, this );
+ // the first call creates the ScBroadcastArea
+ (*pp)->StartListeningArea( rRange, pListener, pArea );
+ if ( nOff < nBreak )
+ {
+ ++nOff;
+ ++pp;
+ }
+ else
+ {
+ nStart += BCA_SLOTS_ROW;
+ nOff = nStart;
+ pp = ppSlots + nOff;
+ nBreak = nOff + nRowBreak;
+ }
+ }
+ }
+}
+
+
+void ScBroadcastAreaSlotMachine::EndListeningArea( const ScRange& rRange,
+ SvtListener* pListener
+ )
+{
+ if ( rRange == BCA_LISTEN_ALWAYS )
+ {
+ DBG_ASSERT( pBCAlways, "ScBroadcastAreaSlotMachine::EndListeningArea: BCA_LISTEN_ALWAYS but none established");
+ if ( pBCAlways )
+ {
+ pListener->EndListening( *pBCAlways);
+ if (!pBCAlways->HasListeners())
+ {
+ delete pBCAlways;
+ pBCAlways = NULL;
+ }
+ }
+ }
+ else
+ {
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ ScBroadcastArea* pArea = NULL;
+ while ( nOff <= nEnd )
+ {
+ if ( *pp )
+ (*pp)->EndListeningArea( rRange, pListener, pArea );
+ if ( nOff < nBreak )
+ {
+ ++nOff;
+ ++pp;
+ }
+ else
+ {
+ nStart += BCA_SLOTS_ROW;
+ nOff = nStart;
+ pp = ppSlots + nOff;
+ nBreak = nOff + nRowBreak;
+ }
+ }
+ }
+}
+
+
+BOOL ScBroadcastAreaSlotMachine::AreaBroadcast( const ScHint& rHint ) const
+{
+ const ScAddress& rAddress = rHint.GetAddress();
+ if ( rAddress == BCA_BRDCST_ALWAYS )
+ {
+ if ( pBCAlways )
+ {
+ pBCAlways->Broadcast( rHint );
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+ else
+ {
+ ScBroadcastAreaSlot* pSlot = ppSlots[ ComputeSlotOffset( rAddress ) ];
+ if ( pSlot )
+ return pSlot->AreaBroadcast( rHint );
+ else
+ return FALSE;
+ }
+}
+
+
+BOOL ScBroadcastAreaSlotMachine::AreaBroadcastInRange( const ScRange& rRange,
+ const ScHint& rHint ) const
+{
+ BOOL bBroadcasted = FALSE;
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ while ( nOff <= nEnd )
+ {
+ if ( *pp )
+ bBroadcasted |= (*pp)->AreaBroadcastInRange( rRange, rHint );
+ if ( nOff < nBreak )
+ {
+ ++nOff;
+ ++pp;
+ }
+ else
+ {
+ nStart += BCA_SLOTS_ROW;
+ nOff = nStart;
+ pp = ppSlots + nOff;
+ nBreak = nOff + nRowBreak;
+ }
+ }
+ return bBroadcasted;
+}
+
+
+void ScBroadcastAreaSlotMachine::DelBroadcastAreasInRange(
+ const ScRange& rRange
+ )
+{
+ SCSIZE nStart, nEnd, nRowBreak;
+ ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ while ( nOff <= nEnd )
+ {
+ if ( *pp )
+ (*pp)->DelBroadcastAreasInRange( rRange );
+ if ( nOff < nBreak )
+ {
+ ++nOff;
+ ++pp;
+ }
+ else
+ {
+ nStart += BCA_SLOTS_ROW;
+ nOff = nStart;
+ pp = ppSlots + nOff;
+ nBreak = nOff + nRowBreak;
+ }
+ }
+}
+
+
+// for all affected: remove, chain, update range, insert
+void ScBroadcastAreaSlotMachine::UpdateBroadcastAreas(
+ UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz
+ )
+{
+ SCSIZE nStart, nEnd, nRowBreak;
+ // remove affected and put in chain
+ ComputeAreaPoints( rRange, nStart, nEnd, nRowBreak );
+ SCSIZE nOff = nStart;
+ SCSIZE nBreak = nOff + nRowBreak;
+ ScBroadcastAreaSlot** pp = ppSlots + nOff;
+ while ( nOff <= nEnd )
+ {
+ if ( *pp )
+ (*pp)->UpdateRemove( eUpdateRefMode, rRange, nDx, nDy, nDz );
+ if ( nOff < nBreak )
+ {
+ ++nOff;
+ ++pp;
+ }
+ else
+ {
+ nStart += BCA_SLOTS_ROW;
+ nOff = nStart;
+ pp = ppSlots + nOff;
+ nBreak = nOff + nRowBreak;
+ }
+ }
+ // work off chain
+ SCCOL nCol1, nCol2, theCol1, theCol2;
+ SCROW nRow1, nRow2, theRow1, theRow2;
+ SCTAB nTab1, nTab2, theTab1, theTab2;
+ nCol1 = rRange.aStart.Col();
+ nRow1 = rRange.aStart.Row();
+ nTab1 = rRange.aStart.Tab();
+ nCol2 = rRange.aEnd.Col();
+ nRow2 = rRange.aEnd.Row();
+ nTab2 = rRange.aEnd.Tab();
+ while ( pUpdateChain )
+ {
+ ScAddress aAdr;
+ ScRange aRange;
+ ScBroadcastArea* pArea = pUpdateChain;
+ pUpdateChain = pArea->GetUpdateChainNext();
+
+ // update range
+ aAdr = pArea->GetStart();
+ theCol1 = aAdr.Col();
+ theRow1 = aAdr.Row();
+ theTab1 = aAdr.Tab();
+ aAdr = pArea->GetEnd();
+ theCol2 = aAdr.Col();
+ theRow2 = aAdr.Row();
+ theTab2 = aAdr.Tab();
+ if ( ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
+ theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 )
+ )
+ {
+ aRange = ScRange( ScAddress( theCol1,theRow1,theTab1 ),
+ ScAddress( theCol2,theRow2,theTab2 ) );
+ pArea->UpdateRange( aRange );
+ pArea->GetBroadcaster().Broadcast( ScAreaChangedHint( aRange ) ); // for DDE
+ }
+
+ // insert in slot
+ ComputeAreaPoints( aRange, nStart, nEnd, nRowBreak );
+ nOff = nStart;
+ nBreak = nOff + nRowBreak;
+ pp = ppSlots + nOff;
+ while ( nOff <= nEnd )
+ {
+ if ( *pp )
+ (*pp)->UpdateInsert( pArea );
+ if ( nOff < nBreak )
+ {
+ ++nOff;
+ ++pp;
+ }
+ else
+ {
+ nStart += BCA_SLOTS_ROW;
+ nOff = nStart;
+ pp = ppSlots + nOff;
+ nBreak = nOff + nRowBreak;
+ }
+ }
+
+ // unchain
+ pArea->SetUpdateChainNext( NULL );
+ pArea->SetInUpdateChain( FALSE );
+ }
+ pEOUpdateChain = NULL;
+}
+
+
+void ScBroadcastAreaSlotMachine::EnterBulkBroadcast()
+{
+ ++nInBulkBroadcast;
+}
+
+
+void ScBroadcastAreaSlotMachine::LeaveBulkBroadcast()
+{
+ if (nInBulkBroadcast > 0)
+ {
+ if (--nInBulkBroadcast == 0)
+ ScBroadcastAreasBulk().swap( aBulkBroadcastAreas);
+ }
+}
+
+
+bool ScBroadcastAreaSlotMachine::InsertBulkArea( const ScBroadcastArea* pArea )
+{
+ return aBulkBroadcastAreas.insert( pArea ).second;
+}
+
+
+size_t ScBroadcastAreaSlotMachine::RemoveBulkArea( const ScBroadcastArea* pArea )
+{
+ return aBulkBroadcastAreas.erase( pArea );
+}
diff --git a/sc/source/core/data/cell.cxx b/sc/source/core/data/cell.cxx
new file mode 100644
index 000000000000..0d71db3427b0
--- /dev/null
+++ b/sc/source/core/data/cell.cxx
@@ -0,0 +1,1987 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: cell.cxx,v $
+ * $Revision: 1.44.38.6 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <svtools/zforlist.hxx>
+
+#include "scitems.hxx"
+#include "attrib.hxx"
+#include "cell.hxx"
+#include "compiler.hxx"
+#include "interpre.hxx"
+#include "document.hxx"
+#include "scmatrix.hxx"
+#include "dociter.hxx"
+#include "docoptio.hxx"
+#include "rechead.hxx"
+#include "rangenam.hxx"
+#include "brdcst.hxx"
+#include "ddelink.hxx"
+#include "validat.hxx"
+#include "progress.hxx"
+#include "editutil.hxx"
+#include "recursionhelper.hxx"
+#include "postit.hxx"
+#include "externalrefmgr.hxx"
+#include <svx/editobj.hxx>
+#include <svtools/intitem.hxx>
+#include <svx/flditem.hxx>
+#include <svtools/broadcast.hxx>
+
+using namespace formula;
+// More or less arbitrary, of course all recursions must fit into available
+// stack space (which is what on all systems we don't know yet?). Choosing a
+// lower value may be better than trying a much higher value that also isn't
+// sufficient but temporarily leads to high memory consumption. On the other
+// hand, if the value fits all recursions, execution is quicker as no resumes
+// are necessary. Could be made a configurable option.
+// Allow for a year's calendar (366).
+const USHORT MAXRECURSION = 400;
+
+// STATIC DATA -----------------------------------------------------------
+
+#ifdef USE_MEMPOOL
+// MemPools auf 4k Boundaries - 64 Bytes ausrichten
+const USHORT nMemPoolValueCell = (0x8000 - 64) / sizeof(ScValueCell);
+const USHORT nMemPoolFormulaCell = (0x8000 - 64) / sizeof(ScFormulaCell);
+const USHORT nMemPoolStringCell = (0x4000 - 64) / sizeof(ScStringCell);
+const USHORT nMemPoolNoteCell = (0x1000 - 64) / sizeof(ScNoteCell);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScValueCell, nMemPoolValueCell, nMemPoolValueCell )
+IMPL_FIXEDMEMPOOL_NEWDEL( ScFormulaCell, nMemPoolFormulaCell, nMemPoolFormulaCell )
+IMPL_FIXEDMEMPOOL_NEWDEL( ScStringCell, nMemPoolStringCell, nMemPoolStringCell )
+IMPL_FIXEDMEMPOOL_NEWDEL( ScNoteCell, nMemPoolNoteCell, nMemPoolNoteCell )
+#endif
+
+// ============================================================================
+
+ScBaseCell::ScBaseCell( CellType eNewType ) :
+ mpNote( 0 ),
+ mpBroadcaster( 0 ),
+ nTextWidth( TEXTWIDTH_DIRTY ),
+ eCellType( sal::static_int_cast<BYTE>(eNewType) ),
+ nScriptType( SC_SCRIPTTYPE_UNKNOWN )
+{
+}
+
+ScBaseCell::ScBaseCell( const ScBaseCell& rCell ) :
+ mpNote( 0 ),
+ mpBroadcaster( 0 ),
+ nTextWidth( rCell.nTextWidth ),
+ eCellType( rCell.eCellType ),
+ nScriptType( SC_SCRIPTTYPE_UNKNOWN )
+{
+}
+
+ScBaseCell::~ScBaseCell()
+{
+ delete mpNote;
+ delete mpBroadcaster;
+ DBG_ASSERT( eCellType == CELLTYPE_DESTROYED, "BaseCell Destructor" );
+}
+
+namespace {
+
+ScBaseCell* lclCloneCell( const ScBaseCell& rSrcCell, ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags )
+{
+ switch( rSrcCell.GetCellType() )
+ {
+ case CELLTYPE_VALUE:
+ return new ScValueCell( static_cast< const ScValueCell& >( rSrcCell ) );
+ case CELLTYPE_STRING:
+ return new ScStringCell( static_cast< const ScStringCell& >( rSrcCell ) );
+ case CELLTYPE_EDIT:
+ return new ScEditCell( static_cast< const ScEditCell& >( rSrcCell ), rDestDoc );
+ case CELLTYPE_FORMULA:
+ return new ScFormulaCell( static_cast< const ScFormulaCell& >( rSrcCell ), rDestDoc, rDestPos, nCloneFlags );
+ case CELLTYPE_NOTE:
+ return new ScNoteCell;
+ default:;
+ }
+ DBG_ERROR( "lclCloneCell - unknown cell type" );
+ return 0;
+}
+
+} // namespace
+
+ScBaseCell* ScBaseCell::CloneWithoutNote( ScDocument& rDestDoc, int nCloneFlags ) const
+{
+ // notes will not be cloned -> cell address only needed for formula cells
+ ScAddress aDestPos;
+ if( eCellType == CELLTYPE_FORMULA )
+ aDestPos = static_cast< const ScFormulaCell* >( this )->aPos;
+ return lclCloneCell( *this, rDestDoc, aDestPos, nCloneFlags );
+}
+
+ScBaseCell* ScBaseCell::CloneWithoutNote( ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags ) const
+{
+ return lclCloneCell( *this, rDestDoc, rDestPos, nCloneFlags );
+}
+
+ScBaseCell* ScBaseCell::CloneWithNote( ScDocument& rDestDoc, const ScAddress& rDestPos, int nCloneFlags ) const
+{
+ ScBaseCell* pNewCell = lclCloneCell( *this, rDestDoc, rDestPos, nCloneFlags );
+ if( mpNote )
+ {
+ if( !pNewCell )
+ pNewCell = new ScNoteCell;
+ bool bCloneCaption = (nCloneFlags & SC_CLONECELL_NOCAPTION) == 0;
+ pNewCell->TakeNote( ScNoteUtil::CloneNote( rDestDoc, rDestPos, *mpNote, bCloneCaption ) );
+ }
+ return pNewCell;
+}
+
+void ScBaseCell::Delete()
+{
+ DeleteNote();
+ switch (eCellType)
+ {
+ case CELLTYPE_VALUE:
+ delete (ScValueCell*) this;
+ break;
+ case CELLTYPE_STRING:
+ delete (ScStringCell*) this;
+ break;
+ case CELLTYPE_EDIT:
+ delete (ScEditCell*) this;
+ break;
+ case CELLTYPE_FORMULA:
+ delete (ScFormulaCell*) this;
+ break;
+ case CELLTYPE_NOTE:
+ delete (ScNoteCell*) this;
+ break;
+ default:
+ DBG_ERROR("Unbekannter Zellentyp");
+ break;
+ }
+}
+
+bool ScBaseCell::IsBlank( bool bIgnoreNotes ) const
+{
+ return (eCellType == CELLTYPE_NOTE) && (bIgnoreNotes || !mpNote);
+}
+
+void ScBaseCell::TakeNote( ScPostIt* pNote )
+{
+ delete mpNote;
+ mpNote = pNote;
+}
+
+ScPostIt* ScBaseCell::ReleaseNote()
+{
+ ScPostIt* pNote = mpNote;
+ mpNote = 0;
+ return pNote;
+}
+
+void ScBaseCell::DeleteNote()
+{
+ DELETEZ( mpNote );
+}
+
+void ScBaseCell::TakeBroadcaster( SvtBroadcaster* pBroadcaster )
+{
+ delete mpBroadcaster;
+ mpBroadcaster = pBroadcaster;
+}
+
+SvtBroadcaster* ScBaseCell::ReleaseBroadcaster()
+{
+ SvtBroadcaster* pBroadcaster = mpBroadcaster;
+ mpBroadcaster = 0;
+ return pBroadcaster;
+}
+
+void ScBaseCell::DeleteBroadcaster()
+{
+ DELETEZ( mpBroadcaster );
+}
+
+ScBaseCell* ScBaseCell::CreateTextCell( const String& rString, ScDocument* pDoc )
+{
+ if ( rString.Search('\n') != STRING_NOTFOUND || rString.Search(CHAR_CR) != STRING_NOTFOUND )
+ return new ScEditCell( rString, pDoc );
+ else
+ return new ScStringCell( rString );
+}
+
+void ScBaseCell::StartListeningTo( ScDocument* pDoc )
+{
+ if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo()
+ && !pDoc->GetNoListening()
+ && !((ScFormulaCell*)this)->IsInChangeTrack()
+ )
+ {
+ pDoc->SetDetectiveDirty(TRUE); // es hat sich was geaendert...
+
+ ScFormulaCell* pFormCell = (ScFormulaCell*)this;
+ ScTokenArray* pArr = pFormCell->GetCode();
+ if( pArr->IsRecalcModeAlways() )
+ pDoc->StartListeningArea( BCA_LISTEN_ALWAYS, pFormCell );
+ else
+ {
+ pArr->Reset();
+ ScToken* t;
+ while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
+ {
+ StackVar eType = t->GetType();
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ ScSingleRefData& rRef2 = (eType == svDoubleRef ?
+ t->GetDoubleRef().Ref2 : rRef1);
+ switch( eType )
+ {
+ case svSingleRef:
+ rRef1.CalcAbsIfRel( pFormCell->aPos );
+ if ( rRef1.Valid() )
+ {
+ pDoc->StartListeningCell(
+ ScAddress( rRef1.nCol,
+ rRef1.nRow,
+ rRef1.nTab ), pFormCell );
+ }
+ break;
+ case svDoubleRef:
+ t->CalcAbsIfRel( pFormCell->aPos );
+ if ( rRef1.Valid() && rRef2.Valid() )
+ {
+ if ( t->GetOpCode() == ocColRowNameAuto )
+ { // automagically
+ if ( rRef1.IsColRel() )
+ { // ColName
+ pDoc->StartListeningArea( ScRange (
+ 0,
+ rRef1.nRow,
+ rRef1.nTab,
+ MAXCOL,
+ rRef2.nRow,
+ rRef2.nTab ), pFormCell );
+ }
+ else
+ { // RowName
+ pDoc->StartListeningArea( ScRange (
+ rRef1.nCol,
+ 0,
+ rRef1.nTab,
+ rRef2.nCol,
+ MAXROW,
+ rRef2.nTab ), pFormCell );
+ }
+ }
+ else
+ {
+ pDoc->StartListeningArea( ScRange (
+ rRef1.nCol,
+ rRef1.nRow,
+ rRef1.nTab,
+ rRef2.nCol,
+ rRef2.nRow,
+ rRef2.nTab ), pFormCell );
+ }
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ }
+ pFormCell->SetNeedsListening( FALSE);
+ }
+}
+
+// pArr gesetzt -> Referenzen von anderer Zelle nehmen
+// dann muss auch aPos uebergeben werden!
+
+void ScBaseCell::EndListeningTo( ScDocument* pDoc, ScTokenArray* pArr,
+ ScAddress aPos )
+{
+ if ( eCellType == CELLTYPE_FORMULA && !pDoc->IsClipOrUndo()
+ && !((ScFormulaCell*)this)->IsInChangeTrack()
+ )
+ {
+ pDoc->SetDetectiveDirty(TRUE); // es hat sich was geaendert...
+
+ ScFormulaCell* pFormCell = (ScFormulaCell*)this;
+ if( pFormCell->GetCode()->IsRecalcModeAlways() )
+ pDoc->EndListeningArea( BCA_LISTEN_ALWAYS, pFormCell );
+ else
+ {
+ if (!pArr)
+ {
+ pArr = pFormCell->GetCode();
+ aPos = pFormCell->aPos;
+ }
+ pArr->Reset();
+ ScToken* t;
+ while ( ( t = static_cast<ScToken*>(pArr->GetNextReferenceRPN()) ) != NULL )
+ {
+ StackVar eType = t->GetType();
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ ScSingleRefData& rRef2 = (eType == svDoubleRef ?
+ t->GetDoubleRef().Ref2 : rRef1);
+ switch( eType )
+ {
+ case svSingleRef:
+ rRef1.CalcAbsIfRel( aPos );
+ if ( rRef1.Valid() )
+ {
+ pDoc->EndListeningCell(
+ ScAddress( rRef1.nCol,
+ rRef1.nRow,
+ rRef1.nTab ), pFormCell );
+ }
+ break;
+ case svDoubleRef:
+ t->CalcAbsIfRel( aPos );
+ if ( rRef1.Valid() && rRef2.Valid() )
+ {
+ if ( t->GetOpCode() == ocColRowNameAuto )
+ { // automagically
+ if ( rRef1.IsColRel() )
+ { // ColName
+ pDoc->EndListeningArea( ScRange (
+ 0,
+ rRef1.nRow,
+ rRef1.nTab,
+ MAXCOL,
+ rRef2.nRow,
+ rRef2.nTab ), pFormCell );
+ }
+ else
+ { // RowName
+ pDoc->EndListeningArea( ScRange (
+ rRef1.nCol,
+ 0,
+ rRef1.nTab,
+ rRef2.nCol,
+ MAXROW,
+ rRef2.nTab ), pFormCell );
+ }
+ }
+ else
+ {
+ pDoc->EndListeningArea( ScRange (
+ rRef1.nCol,
+ rRef1.nRow,
+ rRef1.nTab,
+ rRef2.nCol,
+ rRef2.nRow,
+ rRef2.nTab ), pFormCell );
+ }
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ }
+ }
+}
+
+
+USHORT ScBaseCell::GetErrorCode() const
+{
+ switch ( eCellType )
+ {
+ case CELLTYPE_FORMULA :
+ return ((ScFormulaCell*)this)->GetErrCode();
+ default:
+ return 0;
+ }
+}
+
+
+BOOL ScBaseCell::HasEmptyData() const
+{
+ switch ( eCellType )
+ {
+ case CELLTYPE_NOTE :
+ return TRUE;
+ case CELLTYPE_FORMULA :
+ return ((ScFormulaCell*)this)->IsEmpty();
+ default:
+ return FALSE;
+ }
+}
+
+
+BOOL ScBaseCell::HasValueData() const
+{
+ switch ( eCellType )
+ {
+ case CELLTYPE_VALUE :
+ return TRUE;
+ case CELLTYPE_FORMULA :
+ return ((ScFormulaCell*)this)->IsValue();
+ default:
+ return FALSE;
+ }
+}
+
+
+BOOL ScBaseCell::HasStringData() const
+{
+ switch ( eCellType )
+ {
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ return TRUE;
+ case CELLTYPE_FORMULA :
+ return !((ScFormulaCell*)this)->IsValue();
+ default:
+ return FALSE;
+ }
+}
+
+String ScBaseCell::GetStringData() const
+{
+ String aStr;
+ switch ( eCellType )
+ {
+ case CELLTYPE_STRING:
+ ((const ScStringCell*)this)->GetString( aStr );
+ break;
+ case CELLTYPE_EDIT:
+ ((const ScEditCell*)this)->GetString( aStr );
+ break;
+ case CELLTYPE_FORMULA:
+ ((ScFormulaCell*)this)->GetString( aStr ); // an der Formelzelle nicht-const
+ break;
+ }
+ return aStr;
+}
+
+// static
+BOOL ScBaseCell::CellEqual( const ScBaseCell* pCell1, const ScBaseCell* pCell2 )
+{
+ CellType eType1 = CELLTYPE_NONE;
+ CellType eType2 = CELLTYPE_NONE;
+ if ( pCell1 )
+ {
+ eType1 = pCell1->GetCellType();
+ if (eType1 == CELLTYPE_EDIT)
+ eType1 = CELLTYPE_STRING;
+ else if (eType1 == CELLTYPE_NOTE)
+ eType1 = CELLTYPE_NONE;
+ }
+ if ( pCell2 )
+ {
+ eType2 = pCell2->GetCellType();
+ if (eType2 == CELLTYPE_EDIT)
+ eType2 = CELLTYPE_STRING;
+ else if (eType2 == CELLTYPE_NOTE)
+ eType2 = CELLTYPE_NONE;
+ }
+ if ( eType1 != eType2 )
+ return FALSE;
+
+ switch ( eType1 ) // beide Typen gleich
+ {
+ case CELLTYPE_NONE: // beide leer
+ return TRUE;
+ case CELLTYPE_VALUE: // wirklich Value-Zellen
+ return ( ((const ScValueCell*)pCell1)->GetValue() ==
+ ((const ScValueCell*)pCell2)->GetValue() );
+ case CELLTYPE_STRING: // String oder Edit
+ {
+ String aText1;
+ if ( pCell1->GetCellType() == CELLTYPE_STRING )
+ ((const ScStringCell*)pCell1)->GetString(aText1);
+ else
+ ((const ScEditCell*)pCell1)->GetString(aText1);
+ String aText2;
+ if ( pCell2->GetCellType() == CELLTYPE_STRING )
+ ((const ScStringCell*)pCell2)->GetString(aText2);
+ else
+ ((const ScEditCell*)pCell2)->GetString(aText2);
+ return ( aText1 == aText2 );
+ }
+ case CELLTYPE_FORMULA:
+ {
+ //! eingefuegte Zeilen / Spalten beruecksichtigen !!!!!
+ //! Vergleichsfunktion an der Formelzelle ???
+ //! Abfrage mit ScColumn::SwapRow zusammenfassen!
+
+ ScTokenArray* pCode1 = ((ScFormulaCell*)pCell1)->GetCode();
+ ScTokenArray* pCode2 = ((ScFormulaCell*)pCell2)->GetCode();
+
+ if (pCode1->GetLen() == pCode2->GetLen()) // nicht-UPN
+ {
+ BOOL bEqual = TRUE;
+ USHORT nLen = pCode1->GetLen();
+ FormulaToken** ppToken1 = pCode1->GetArray();
+ FormulaToken** ppToken2 = pCode2->GetArray();
+ for (USHORT i=0; i<nLen; i++)
+ if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) )
+ {
+ bEqual = FALSE;
+ break;
+ }
+
+ if (bEqual)
+ return TRUE;
+ }
+
+ return FALSE; // unterschiedlich lang oder unterschiedliche Tokens
+ }
+ default:
+ DBG_ERROR("huch, was fuer Zellen???");
+ }
+ return FALSE;
+}
+
+// ============================================================================
+
+ScNoteCell::ScNoteCell( SvtBroadcaster* pBC ) :
+ ScBaseCell( CELLTYPE_NOTE )
+{
+ TakeBroadcaster( pBC );
+}
+
+ScNoteCell::ScNoteCell( ScPostIt* pNote, SvtBroadcaster* pBC ) :
+ ScBaseCell( CELLTYPE_NOTE )
+{
+ TakeNote( pNote );
+ TakeBroadcaster( pBC );
+}
+
+#ifdef DBG_UTIL
+ScNoteCell::~ScNoteCell()
+{
+ eCellType = CELLTYPE_DESTROYED;
+}
+#endif
+
+ScNoteCell::ScNoteCell( SvStream& rStream, USHORT nVer ) :
+ ScBaseCell( CELLTYPE_NOTE )
+{
+ if( nVer >= SC_DATABYTES2 )
+ {
+ BYTE cData;
+ rStream >> cData;
+ if( cData & 0x0F )
+ rStream.SeekRel( cData & 0x0F );
+ }
+}
+
+void ScNoteCell::Save( SvStream& rStream ) const
+{
+ rStream << (BYTE) 0x00;
+}
+
+// ============================================================================
+
+ScValueCell::ScValueCell() :
+ ScBaseCell( CELLTYPE_VALUE ),
+ mfValue( 0.0 )
+{
+}
+
+ScValueCell::ScValueCell( double fValue ) :
+ ScBaseCell( CELLTYPE_VALUE ),
+ mfValue( fValue )
+{
+}
+
+#ifdef DBG_UTIL
+ScValueCell::~ScValueCell()
+{
+ eCellType = CELLTYPE_DESTROYED;
+}
+#endif
+
+// ============================================================================
+
+ScStringCell::ScStringCell() :
+ ScBaseCell( CELLTYPE_STRING )
+{
+}
+
+ScStringCell::ScStringCell( const String& rString ) :
+ ScBaseCell( CELLTYPE_STRING ),
+ maString( rString.intern() )
+{
+}
+
+#ifdef DBG_UTIL
+ScStringCell::~ScStringCell()
+{
+ eCellType = CELLTYPE_DESTROYED;
+}
+#endif
+
+// ============================================================================
+
+//
+// ScFormulaCell
+//
+
+ScFormulaCell::ScFormulaCell() :
+ ScBaseCell( CELLTYPE_FORMULA ),
+ eTempGrammar( FormulaGrammar::GRAM_DEFAULT),
+ pCode( NULL ),
+ pDocument( NULL ),
+ pPrevious(0),
+ pNext(0),
+ pPreviousTrack(0),
+ pNextTrack(0),
+ nFormatIndex(0),
+ nFormatType( NUMBERFORMAT_NUMBER ),
+ nSeenInIteration(0),
+ cMatrixFlag ( MM_NONE ),
+ bDirty( FALSE ),
+ bChanged( FALSE ),
+ bRunning( FALSE ),
+ bCompile( FALSE ),
+ bSubTotal( FALSE ),
+ bIsIterCell( FALSE ),
+ bInChangeTrack( FALSE ),
+ bTableOpDirty( FALSE ),
+ bNeedListening( FALSE ),
+ aPos(0,0,0)
+{
+}
+
+ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
+ const String& rFormula,
+ const FormulaGrammar::Grammar eGrammar,
+ BYTE cMatInd ) :
+ ScBaseCell( CELLTYPE_FORMULA ),
+ eTempGrammar( eGrammar),
+ pCode( NULL ),
+ pDocument( pDoc ),
+ pPrevious(0),
+ pNext(0),
+ pPreviousTrack(0),
+ pNextTrack(0),
+ nFormatIndex(0),
+ nFormatType( NUMBERFORMAT_NUMBER ),
+ nSeenInIteration(0),
+ cMatrixFlag ( cMatInd ),
+ bDirty( TRUE ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cMatInd != 0
+ bChanged( FALSE ),
+ bRunning( FALSE ),
+ bCompile( FALSE ),
+ bSubTotal( FALSE ),
+ bIsIterCell( FALSE ),
+ bInChangeTrack( FALSE ),
+ bTableOpDirty( FALSE ),
+ bNeedListening( FALSE ),
+ aPos( rPos )
+{
+ Compile( rFormula, TRUE, eGrammar ); // bNoListening, Insert does that
+}
+
+// Wird von den Importfiltern verwendet
+
+ScFormulaCell::ScFormulaCell( ScDocument* pDoc, const ScAddress& rPos,
+ const ScTokenArray* pArr,
+ const FormulaGrammar::Grammar eGrammar, BYTE cInd ) :
+ ScBaseCell( CELLTYPE_FORMULA ),
+ eTempGrammar( eGrammar),
+ pCode( pArr ? new ScTokenArray( *pArr ) : new ScTokenArray ),
+ pDocument( pDoc ),
+ pPrevious(0),
+ pNext(0),
+ pPreviousTrack(0),
+ pNextTrack(0),
+ nFormatIndex(0),
+ nFormatType( NUMBERFORMAT_NUMBER ),
+ nSeenInIteration(0),
+ cMatrixFlag ( cInd ),
+ bDirty( NULL != pArr ), // -> wg. Benutzung im Fkt.AutoPiloten, war: cInd != 0
+ bChanged( FALSE ),
+ bRunning( FALSE ),
+ bCompile( FALSE ),
+ bSubTotal( FALSE ),
+ bIsIterCell( FALSE ),
+ bInChangeTrack( FALSE ),
+ bTableOpDirty( FALSE ),
+ bNeedListening( FALSE ),
+ aPos( rPos )
+{
+ // UPN-Array erzeugen
+ if( pCode->GetLen() && !pCode->GetCodeError() && !pCode->GetCodeLen() )
+ {
+ ScCompiler aComp( pDocument, aPos, *pCode);
+ aComp.SetGrammar(eTempGrammar);
+ bSubTotal = aComp.CompileTokenArray();
+ nFormatType = aComp.GetNumFormatType();
+ }
+ else
+ {
+ pCode->Reset();
+ if ( pCode->GetNextOpCodeRPN( ocSubTotal ) )
+ bSubTotal = TRUE;
+ }
+}
+
+ScFormulaCell::ScFormulaCell( const ScFormulaCell& rCell, ScDocument& rDoc, const ScAddress& rPos, int nCloneFlags ) :
+ ScBaseCell( rCell ),
+ SvtListener(),
+ aResult( rCell.aResult ),
+ eTempGrammar( rCell.eTempGrammar),
+ pDocument( &rDoc ),
+ pPrevious(0),
+ pNext(0),
+ pPreviousTrack(0),
+ pNextTrack(0),
+ nFormatIndex( &rDoc == rCell.pDocument ? rCell.nFormatIndex : 0 ),
+ nFormatType( rCell.nFormatType ),
+ nSeenInIteration(0),
+ cMatrixFlag ( rCell.cMatrixFlag ),
+ bDirty( rCell.bDirty ),
+ bChanged( rCell.bChanged ),
+ bRunning( FALSE ),
+ bCompile( rCell.bCompile ),
+ bSubTotal( rCell.bSubTotal ),
+ bIsIterCell( FALSE ),
+ bInChangeTrack( FALSE ),
+ bTableOpDirty( FALSE ),
+ bNeedListening( FALSE ),
+ aPos( rPos )
+{
+ pCode = rCell.pCode->Clone();
+
+ if ( nCloneFlags & SC_CLONECELL_ADJUST3DREL )
+ pCode->ReadjustRelative3DReferences( rCell.aPos, aPos );
+
+ // evtl. Fehler zuruecksetzen und neu kompilieren
+ // nicht im Clipboard - da muss das Fehlerflag erhalten bleiben
+ // Spezialfall Laenge=0: als Fehlerzelle erzeugt, dann auch Fehler behalten
+ if ( pCode->GetCodeError() && !pDocument->IsClipboard() && pCode->GetLen() )
+ {
+ pCode->SetCodeError( 0 );
+ bCompile = TRUE;
+ }
+ //! Compile ColRowNames on URM_MOVE/URM_COPY _after_ UpdateReference
+ BOOL bCompileLater = FALSE;
+ BOOL bClipMode = rCell.pDocument->IsClipboard();
+ if( !bCompile )
+ { // Name references with references and ColRowNames
+ pCode->Reset();
+ ScToken* t;
+ while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceOrName()) ) != NULL && !bCompile )
+ {
+ if ( t->GetOpCode() == ocExternalRef )
+ {
+ // External name, cell, and area references.
+ bCompile = true;
+ }
+ else if ( t->GetType() == svIndex )
+ {
+ ScRangeData* pRangeData = rDoc.GetRangeName()->FindIndex( t->GetIndex() );
+ if( pRangeData )
+ {
+ if( pRangeData->HasReferences() )
+ bCompile = TRUE;
+ }
+ else
+ bCompile = TRUE; // invalid reference!
+ }
+ else if ( t->GetOpCode() == ocColRowName )
+ {
+ bCompile = TRUE; // new lookup needed
+ bCompileLater = bClipMode;
+ }
+ }
+ }
+ if( bCompile )
+ {
+ if ( !bCompileLater && bClipMode )
+ {
+ // Merging ranges needs the actual positions after UpdateReference.
+ // ColRowNames need new lookup after positions are adjusted.
+ bCompileLater = pCode->HasOpCode( ocRange) || pCode->HasOpCode( ocColRowName);
+ }
+ if ( !bCompileLater )
+ {
+ // bNoListening, not at all if in Clipboard/Undo,
+ // and not from Clipboard either, instead after Insert(Clone) and UpdateReference.
+ CompileTokenArray( TRUE );
+ }
+ }
+
+ if( nCloneFlags & SC_CLONECELL_STARTLISTENING )
+ StartListeningTo( &rDoc );
+}
+
+ScFormulaCell::~ScFormulaCell()
+{
+ pDocument->RemoveFromFormulaTree( this );
+ delete pCode;
+#ifdef DBG_UTIL
+ eCellType = CELLTYPE_DESTROYED;
+#endif
+}
+
+void ScFormulaCell::GetFormula( rtl::OUStringBuffer& rBuffer,
+ const FormulaGrammar::Grammar eGrammar ) const
+{
+ if( pCode->GetCodeError() && !pCode->GetLen() )
+ {
+ rBuffer = rtl::OUStringBuffer( ScGlobal::GetErrorString( pCode->GetCodeError()));
+ return;
+ }
+ else if( cMatrixFlag == MM_REFERENCE )
+ {
+ // Reference to another cell that contains a matrix formula.
+ pCode->Reset();
+ ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
+ if( p )
+ {
+ /* FIXME: original GetFormula() code obtained
+ * pCell only if (!this->IsInChangeTrack()),
+ * GetEnglishFormula() omitted that test.
+ * Can we live without in all cases? */
+ ScBaseCell* pCell;
+ ScSingleRefData& rRef = p->GetSingleRef();
+ rRef.CalcAbsIfRel( aPos );
+ if ( rRef.Valid() )
+ pCell = pDocument->GetCell( ScAddress( rRef.nCol,
+ rRef.nRow, rRef.nTab ) );
+ else
+ pCell = NULL;
+ if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ ((ScFormulaCell*)pCell)->GetFormula( rBuffer, eGrammar);
+ return;
+ }
+ else
+ {
+ ScCompiler aComp( pDocument, aPos, *pCode);
+ aComp.SetGrammar(eGrammar);
+ aComp.CreateStringFromTokenArray( rBuffer );
+ }
+ }
+ else
+ {
+ DBG_ERROR("ScFormulaCell::GetFormula: not a matrix");
+ }
+ }
+ else
+ {
+ ScCompiler aComp( pDocument, aPos, *pCode);
+ aComp.SetGrammar(eGrammar);
+ aComp.CreateStringFromTokenArray( rBuffer );
+ }
+
+ sal_Unicode ch('=');
+ rBuffer.insert( 0, &ch, 1 );
+ if( cMatrixFlag )
+ {
+ sal_Unicode ch2('{');
+ rBuffer.insert( 0, &ch2, 1);
+ rBuffer.append( sal_Unicode('}'));
+ }
+}
+
+void ScFormulaCell::GetFormula( String& rFormula, const FormulaGrammar::Grammar eGrammar ) const
+{
+ rtl::OUStringBuffer rBuffer( rFormula );
+ GetFormula( rBuffer, eGrammar );
+ rFormula = rBuffer;
+}
+
+void ScFormulaCell::GetResultDimensions( SCSIZE& rCols, SCSIZE& rRows )
+{
+ if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
+ Interpret();
+
+ const ScMatrix* pMat = NULL;
+ if (!pCode->GetCodeError() && aResult.GetType() == svMatrixCell &&
+ ((pMat = static_cast<const ScToken*>(aResult.GetToken().get())->GetMatrix()) != 0))
+ pMat->GetDimensions( rCols, rRows );
+ else
+ {
+ rCols = 0;
+ rRows = 0;
+ }
+}
+
+void ScFormulaCell::Compile( const String& rFormula, BOOL bNoListening,
+ const FormulaGrammar::Grammar eGrammar )
+{
+ if ( pDocument->IsClipOrUndo() ) return;
+ BOOL bWasInFormulaTree = pDocument->IsInFormulaTree( this );
+ if ( bWasInFormulaTree )
+ pDocument->RemoveFromFormulaTree( this );
+ // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein
+ if ( pCode )
+ pCode->Clear();
+ ScTokenArray* pCodeOld = pCode;
+ ScCompiler aComp( pDocument, aPos);
+ aComp.SetGrammar(eGrammar);
+ pCode = aComp.CompileString( rFormula );
+ if ( pCodeOld )
+ delete pCodeOld;
+ if( !pCode->GetCodeError() )
+ {
+ if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() && rFormula == aResult.GetHybridFormula() )
+ { // #65994# nicht rekursiv CompileTokenArray/Compile/CompileTokenArray
+ if ( rFormula.GetChar(0) == '=' )
+ pCode->AddBad( rFormula.GetBuffer() + 1 );
+ else
+ pCode->AddBad( rFormula.GetBuffer() );
+ }
+ bCompile = TRUE;
+ CompileTokenArray( bNoListening );
+ }
+ else
+ {
+ bChanged = TRUE;
+ SetTextWidth( TEXTWIDTH_DIRTY );
+ SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
+ }
+ if ( bWasInFormulaTree )
+ pDocument->PutInFormulaTree( this );
+}
+
+
+void ScFormulaCell::CompileTokenArray( BOOL bNoListening )
+{
+ // Not already compiled?
+ if( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
+ Compile( aResult.GetHybridFormula(), bNoListening, eTempGrammar);
+ else if( bCompile && !pDocument->IsClipOrUndo() && !pCode->GetCodeError() )
+ {
+ // RPN length may get changed
+ BOOL bWasInFormulaTree = pDocument->IsInFormulaTree( this );
+ if ( bWasInFormulaTree )
+ pDocument->RemoveFromFormulaTree( this );
+
+ // Loading from within filter? No listening yet!
+ if( pDocument->IsInsertingFromOtherDoc() )
+ bNoListening = TRUE;
+
+ if( !bNoListening && pCode->GetCodeLen() )
+ EndListeningTo( pDocument );
+ ScCompiler aComp(pDocument, aPos, *pCode);
+ aComp.SetGrammar(pDocument->GetGrammar());
+ bSubTotal = aComp.CompileTokenArray();
+ if( !pCode->GetCodeError() )
+ {
+ nFormatType = aComp.GetNumFormatType();
+ nFormatIndex = 0;
+ bChanged = TRUE;
+ aResult.SetToken( NULL);
+ bCompile = FALSE;
+ if ( !bNoListening )
+ StartListeningTo( pDocument );
+ }
+ if ( bWasInFormulaTree )
+ pDocument->PutInFormulaTree( this );
+ }
+}
+
+
+void ScFormulaCell::CompileXML( ScProgress& rProgress )
+{
+ if ( cMatrixFlag == MM_REFERENCE )
+ { // is already token code via ScDocFunc::EnterMatrix, ScDocument::InsertMatrixFormula
+ // just establish listeners
+ StartListeningTo( pDocument );
+ return ;
+ }
+
+ ScCompiler aComp( pDocument, aPos, *pCode);
+ aComp.SetGrammar(eTempGrammar);
+ String aFormula;
+ aComp.CreateStringFromTokenArray( aFormula );
+ pDocument->DecXMLImportedFormulaCount( aFormula.Len() );
+ rProgress.SetStateCountDownOnPercent( pDocument->GetXMLImportedFormulaCount() );
+ // pCode darf fuer Abfragen noch nicht geloescht, muss aber leer sein
+ if ( pCode )
+ pCode->Clear();
+ ScTokenArray* pCodeOld = pCode;
+ pCode = aComp.CompileString( aFormula );
+ delete pCodeOld;
+ if( !pCode->GetCodeError() )
+ {
+ if ( !pCode->GetLen() )
+ {
+ if ( aFormula.GetChar(0) == '=' )
+ pCode->AddBad( aFormula.GetBuffer() + 1 );
+ else
+ pCode->AddBad( aFormula.GetBuffer() );
+ }
+ bSubTotal = aComp.CompileTokenArray();
+ if( !pCode->GetCodeError() )
+ {
+ nFormatType = aComp.GetNumFormatType();
+ nFormatIndex = 0;
+ bChanged = TRUE;
+ bCompile = FALSE;
+ StartListeningTo( pDocument );
+ }
+ }
+ else
+ {
+ bChanged = TRUE;
+ SetTextWidth( TEXTWIDTH_DIRTY );
+ SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
+ }
+
+ // Same as in Load: after loading, it must be known if ocMacro is in any formula
+ // (for macro warning, CompileXML is called at the end of loading XML file)
+ if ( !pDocument->GetHasMacroFunc() && pCode->HasOpCodeRPN( ocMacro ) )
+ pDocument->SetHasMacroFunc( TRUE );
+}
+
+
+void ScFormulaCell::CalcAfterLoad()
+{
+ BOOL bNewCompiled = FALSE;
+ // Falls ein Calc 1.0-Doc eingelesen wird, haben wir ein Ergebnis,
+ // aber kein TokenArray
+ if( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
+ {
+ Compile( aResult.GetHybridFormula(), TRUE, eTempGrammar);
+ aResult.SetToken( NULL);
+ bDirty = TRUE;
+ bNewCompiled = TRUE;
+ }
+ // Das UPN-Array wird nicht erzeugt, wenn ein Calc 3.0-Doc eingelesen
+ // wurde, da die RangeNames erst jetzt existieren.
+ if( pCode->GetLen() && !pCode->GetCodeLen() && !pCode->GetCodeError() )
+ {
+ ScCompiler aComp(pDocument, aPos, *pCode);
+ aComp.SetGrammar(pDocument->GetGrammar());
+ bSubTotal = aComp.CompileTokenArray();
+ nFormatType = aComp.GetNumFormatType();
+ nFormatIndex = 0;
+ bDirty = TRUE;
+ bCompile = FALSE;
+ bNewCompiled = TRUE;
+ }
+ // irgendwie koennen unter os/2 mit rotter FPU-Exception /0 ohne Err503
+ // gespeichert werden, woraufhin spaeter im NumberFormatter die BLC Lib
+ // bei einem fabs(-NAN) abstuerzt (#32739#)
+ // hier fuer alle Systeme ausbuegeln, damit da auch Err503 steht
+ if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
+ {
+ DBG_ERRORFILE("Formelzelle INFINITY !!! Woher kommt das Dokument?");
+ aResult.SetResultError( errIllegalFPOperation );
+ bDirty = TRUE;
+ }
+ // DoubleRefs bei binaeren Operatoren waren vor v5.0 immer Matrix,
+ // jetzt nur noch wenn in Matrixformel, sonst implizite Schnittmenge
+ if ( pDocument->GetSrcVersion() < SC_MATRIX_DOUBLEREF &&
+ GetMatrixFlag() == MM_NONE && pCode->HasMatrixDoubleRefOps() )
+ {
+ cMatrixFlag = MM_FORMULA;
+ SetMatColsRows( 1, 1);
+ }
+ // Muss die Zelle berechnet werden?
+ // Nach Load koennen Zellen einen Fehlercode enthalten, auch dann
+ // Listener starten und ggbf. neu berechnen wenn nicht RECALCMODE_NORMAL
+ if( !bNewCompiled || !pCode->GetCodeError() )
+ {
+ StartListeningTo( pDocument );
+ if( !pCode->IsRecalcModeNormal() )
+ bDirty = TRUE;
+ }
+ if ( pCode->IsRecalcModeAlways() )
+ { // zufall(), heute(), jetzt() bleiben immer im FormulaTree, damit sie
+ // auch bei jedem F9 berechnet werden.
+ bDirty = TRUE;
+ }
+ // Noch kein SetDirty weil noch nicht alle Listener bekannt, erst in
+ // SetDirtyAfterLoad.
+}
+
+
+bool ScFormulaCell::MarkUsedExternalReferences()
+{
+ return pCode && pDocument->MarkUsedExternalReferences( *pCode);
+}
+
+
+// FIXME: set to 0
+#define erDEBUGDOT 0
+// If set to 1, write output that's suitable for graphviz tools like dot.
+// Only node1 -> node2 entries are written, you'll have to manually surround
+// the file content with [strict] digraph name { ... }
+// The ``strict'' keyword might be necessary in case of multiple identical
+// paths like they occur in iterations, otherwise dot may consume too much
+// memory when generating the layout, or you'll get unreadable output. On the
+// other hand, information about recurring calculation is lost then.
+// Generates output only if variable nDebug is set in debugger, see below.
+// FIXME: currently doesn't cope with iterations and recursions. Code fragments
+// are a leftover from a previous debug session, meant as a pointer.
+#if erDEBUGDOT
+#include <cstdio>
+using ::std::fopen;
+using ::std::fprintf;
+#include <vector>
+static const char aDebugDotFile[] = "ttt_debug.dot";
+#endif
+
+void ScFormulaCell::Interpret()
+{
+
+#if erDEBUGDOT
+ static int nDebug = 0;
+ static const int erDEBUGDOTRUN = 3;
+ static FILE* pDebugFile = 0;
+ static sal_Int32 nDebugRootCount = 0;
+ static unsigned int nDebugPathCount = 0;
+ static ScAddress aDebugLastPos( ScAddress::INITIALIZE_INVALID);
+ static ScAddress aDebugThisPos( ScAddress::INITIALIZE_INVALID);
+ typedef ::std::vector< ByteString > DebugVector;
+ static DebugVector aDebugVec;
+ class DebugElement
+ {
+ public:
+ static void push( ScFormulaCell* pCell )
+ {
+ aDebugThisPos = pCell->aPos;
+ if (aDebugVec.empty())
+ {
+ ByteString aR( "root_");
+ aR += ByteString::CreateFromInt32( ++nDebugRootCount);
+ aDebugVec.push_back( aR);
+ }
+ String aStr;
+ pCell->aPos.Format( aStr, SCA_VALID | SCA_TAB_3D, pCell->GetDocument(),
+ pCell->GetDocument()->GetAddressConvention() );
+ ByteString aB( aStr, RTL_TEXTENCODING_UTF8);
+ aDebugVec.push_back( aB);
+ }
+ static void pop()
+ {
+ aDebugLastPos = aDebugThisPos;
+ if (!aDebugVec.empty())
+ {
+ aDebugVec.pop_back();
+ if (aDebugVec.size() == 1)
+ {
+ aDebugVec.pop_back();
+ aDebugLastPos = ScAddress( ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ }
+ DebugElement( ScFormulaCell* p ) { push(p); }
+ ~DebugElement() { pop(); }
+ };
+ class DebugDot
+ {
+ public:
+ static void out( const char* pColor )
+ {
+ if (nDebug != erDEBUGDOTRUN)
+ return;
+ char pColorString[256];
+ sprintf( pColorString, (*pColor ?
+ ",color=\"%s\",fontcolor=\"%s\"" : "%s%s"), pColor,
+ pColor);
+ size_t n = aDebugVec.size();
+ fprintf( pDebugFile,
+ "\"%s\" -> \"%s\" [label=\"%u\"%s]; // v:%d\n",
+ aDebugVec[n-2].GetBuffer(), aDebugVec[n-1].GetBuffer(),
+ ++nDebugPathCount, pColorString, n-1);
+ fflush( pDebugFile);
+ }
+ };
+ #define erDEBUGDOT_OUT( p ) (DebugDot::out(p))
+ #define erDEBUGDOT_ELEMENT_PUSH( p ) (DebugElement::push(p))
+ #define erDEBUGDOT_ELEMENT_POP() (DebugElement::pop())
+#else
+ #define erDEBUGDOT_OUT( p )
+ #define erDEBUGDOT_ELEMENT_PUSH( p )
+ #define erDEBUGDOT_ELEMENT_POP()
+#endif
+
+ if (!IsDirtyOrInTableOpDirty() || pDocument->GetRecursionHelper().IsInReturn())
+ return; // no double/triple processing
+
+ //! HACK:
+ // Wenn der Aufruf aus einem Reschedule im DdeLink-Update kommt, dirty stehenlassen
+ // Besser: Dde-Link Update ohne Reschedule oder ganz asynchron !!!
+
+ if ( pDocument->IsInDdeLinkUpdate() )
+ return;
+
+#if erDEBUGDOT
+ // set nDebug=1 in debugger to init things
+ if (nDebug == 1)
+ {
+ ++nDebug;
+ pDebugFile = fopen( aDebugDotFile, "a");
+ if (!pDebugFile)
+ nDebug = 0;
+ else
+ nDebug = erDEBUGDOTRUN;
+ }
+ // set nDebug=3 (erDEBUGDOTRUN) in debugger to get any output
+ DebugElement aDebugElem( this);
+ // set nDebug=5 in debugger to close output
+ if (nDebug == 5)
+ {
+ nDebug = 0;
+ fclose( pDebugFile);
+ pDebugFile = 0;
+ }
+#endif
+
+ if (bRunning)
+ {
+
+#if erDEBUGDOT
+ if (!pDocument->GetRecursionHelper().IsDoingIteration() ||
+ aDebugThisPos != aDebugLastPos)
+ erDEBUGDOT_OUT(aDebugThisPos == aDebugLastPos ? "orange" :
+ (pDocument->GetRecursionHelper().GetIteration() ? "blue" :
+ "red"));
+#endif
+
+ if (!pDocument->GetDocOptions().IsIter())
+ {
+ aResult.SetResultError( errCircularReference );
+ return;
+ }
+
+ if (aResult.GetResultError() == errCircularReference)
+ aResult.SetResultError( 0 );
+
+ // Start or add to iteration list.
+ if (!pDocument->GetRecursionHelper().IsDoingIteration() ||
+ !pDocument->GetRecursionHelper().GetRecursionInIterationStack().top()->bIsIterCell)
+ pDocument->GetRecursionHelper().SetInIterationReturn( true);
+
+ return;
+ }
+ // #63038# no multiple interprets for GetErrCode, IsValue, GetValue and
+ // different entry point recursions. Would also lead to premature
+ // convergence in iterations.
+ if (pDocument->GetRecursionHelper().GetIteration() && nSeenInIteration ==
+ pDocument->GetRecursionHelper().GetIteration())
+ return ;
+
+ erDEBUGDOT_OUT( pDocument->GetRecursionHelper().GetIteration() ? "magenta" : "");
+
+ ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
+ BOOL bOldRunning = bRunning;
+ if (rRecursionHelper.GetRecursionCount() > MAXRECURSION)
+ {
+ bRunning = TRUE;
+ rRecursionHelper.SetInRecursionReturn( true);
+ }
+ else
+ {
+ InterpretTail( SCITP_NORMAL);
+ }
+
+ // While leaving a recursion or iteration stack, insert its cells to the
+ // recursion list in reverse order.
+ if (rRecursionHelper.IsInReturn())
+ {
+ if (rRecursionHelper.GetRecursionCount() > 0 ||
+ !rRecursionHelper.IsDoingRecursion())
+ rRecursionHelper.Insert( this, bOldRunning, aResult);
+ bool bIterationFromRecursion = false;
+ bool bResumeIteration = false;
+ do
+ {
+ if ((rRecursionHelper.IsInIterationReturn() &&
+ rRecursionHelper.GetRecursionCount() == 0 &&
+ !rRecursionHelper.IsDoingIteration()) ||
+ bIterationFromRecursion || bResumeIteration)
+ {
+ ScFormulaCell* pIterCell = this; // scope for debug convenience
+ bool & rDone = rRecursionHelper.GetConvergingReference();
+ rDone = false;
+ if (!bIterationFromRecursion && bResumeIteration)
+ {
+ bResumeIteration = false;
+ // Resuming iteration expands the range.
+ ScFormulaRecursionList::const_iterator aOldStart(
+ rRecursionHelper.GetLastIterationStart());
+ rRecursionHelper.ResumeIteration();
+ // Mark new cells being in iteration.
+ for (ScFormulaRecursionList::const_iterator aIter(
+ rRecursionHelper.GetIterationStart()); aIter !=
+ aOldStart; ++aIter)
+ {
+ pIterCell = (*aIter).pCell;
+ pIterCell->bIsIterCell = TRUE;
+ }
+ // Mark older cells dirty again, in case they converted
+ // without accounting for all remaining cells in the circle
+ // that weren't touched so far, e.g. conditional. Restore
+ // backuped result.
+ USHORT nIteration = rRecursionHelper.GetIteration();
+ for (ScFormulaRecursionList::const_iterator aIter(
+ aOldStart); aIter !=
+ rRecursionHelper.GetIterationEnd(); ++aIter)
+ {
+ pIterCell = (*aIter).pCell;
+ if (pIterCell->nSeenInIteration == nIteration)
+ {
+ if (!pIterCell->bDirty || aIter == aOldStart)
+ {
+ pIterCell->aResult = (*aIter).aPreviousResult;
+ }
+ --pIterCell->nSeenInIteration;
+ }
+ pIterCell->bDirty = TRUE;
+ }
+ }
+ else
+ {
+ bResumeIteration = false;
+ // Close circle once.
+ rRecursionHelper.GetList().back().pCell->InterpretTail(
+ SCITP_CLOSE_ITERATION_CIRCLE);
+ // Start at 1, init things.
+ rRecursionHelper.StartIteration();
+ // Mark all cells being in iteration.
+ for (ScFormulaRecursionList::const_iterator aIter(
+ rRecursionHelper.GetIterationStart()); aIter !=
+ rRecursionHelper.GetIterationEnd(); ++aIter)
+ {
+ pIterCell = (*aIter).pCell;
+ pIterCell->bIsIterCell = TRUE;
+ }
+ }
+ bIterationFromRecursion = false;
+ USHORT nIterMax = pDocument->GetDocOptions().GetIterCount();
+ for ( ; rRecursionHelper.GetIteration() <= nIterMax && !rDone;
+ rRecursionHelper.IncIteration())
+ {
+ rDone = true;
+ for ( ScFormulaRecursionList::iterator aIter(
+ rRecursionHelper.GetIterationStart()); aIter !=
+ rRecursionHelper.GetIterationEnd() &&
+ !rRecursionHelper.IsInReturn(); ++aIter)
+ {
+ pIterCell = (*aIter).pCell;
+ if (pIterCell->IsDirtyOrInTableOpDirty() &&
+ rRecursionHelper.GetIteration() !=
+ pIterCell->GetSeenInIteration())
+ {
+ (*aIter).aPreviousResult = pIterCell->aResult;
+ pIterCell->InterpretTail( SCITP_FROM_ITERATION);
+ }
+ rDone = rDone && !pIterCell->IsDirtyOrInTableOpDirty();
+ }
+ if (rRecursionHelper.IsInReturn())
+ {
+ bResumeIteration = true;
+ break; // for
+ // Don't increment iteration.
+ }
+ }
+ if (!bResumeIteration)
+ {
+ if (rDone)
+ {
+ for (ScFormulaRecursionList::const_iterator aIter(
+ rRecursionHelper.GetIterationStart());
+ aIter != rRecursionHelper.GetIterationEnd();
+ ++aIter)
+ {
+ pIterCell = (*aIter).pCell;
+ pIterCell->bIsIterCell = FALSE;
+ pIterCell->nSeenInIteration = 0;
+ pIterCell->bRunning = (*aIter).bOldRunning;
+ }
+ }
+ else
+ {
+ for (ScFormulaRecursionList::const_iterator aIter(
+ rRecursionHelper.GetIterationStart());
+ aIter != rRecursionHelper.GetIterationEnd();
+ ++aIter)
+ {
+ pIterCell = (*aIter).pCell;
+ pIterCell->bIsIterCell = FALSE;
+ pIterCell->nSeenInIteration = 0;
+ pIterCell->bRunning = (*aIter).bOldRunning;
+ // If one cell didn't converge, all cells of this
+ // circular dependency don't, no matter whether
+ // single cells did.
+ pIterCell->bDirty = FALSE;
+ pIterCell->bTableOpDirty = FALSE;
+ pIterCell->aResult.SetResultError( errNoConvergence);
+ pIterCell->bChanged = TRUE;
+ pIterCell->SetTextWidth( TEXTWIDTH_DIRTY);
+ pIterCell->SetScriptType( SC_SCRIPTTYPE_UNKNOWN);
+ }
+ }
+ // End this iteration and remove entries.
+ rRecursionHelper.EndIteration();
+ bResumeIteration = rRecursionHelper.IsDoingIteration();
+ }
+ }
+ if (rRecursionHelper.IsInRecursionReturn() &&
+ rRecursionHelper.GetRecursionCount() == 0 &&
+ !rRecursionHelper.IsDoingRecursion())
+ {
+ bIterationFromRecursion = false;
+ // Iterate over cells known so far, start with the last cell
+ // encountered, inserting new cells if another recursion limit
+ // is reached. Repeat until solved.
+ rRecursionHelper.SetDoingRecursion( true);
+ do
+ {
+ rRecursionHelper.SetInRecursionReturn( false);
+ for (ScFormulaRecursionList::const_iterator aIter(
+ rRecursionHelper.GetStart());
+ !rRecursionHelper.IsInReturn() && aIter !=
+ rRecursionHelper.GetEnd(); ++aIter)
+ {
+ ScFormulaCell* pCell = (*aIter).pCell;
+ if (pCell->IsDirtyOrInTableOpDirty())
+ {
+ pCell->InterpretTail( SCITP_NORMAL);
+ if (!pCell->IsDirtyOrInTableOpDirty() && !pCell->IsIterCell())
+ pCell->bRunning = (*aIter).bOldRunning;
+ }
+ }
+ } while (rRecursionHelper.IsInRecursionReturn());
+ rRecursionHelper.SetDoingRecursion( false);
+ if (rRecursionHelper.IsInIterationReturn())
+ {
+ if (!bResumeIteration)
+ bIterationFromRecursion = true;
+ }
+ else if (bResumeIteration ||
+ rRecursionHelper.IsDoingIteration())
+ rRecursionHelper.GetList().erase(
+ rRecursionHelper.GetStart(),
+ rRecursionHelper.GetLastIterationStart());
+ else
+ rRecursionHelper.Clear();
+ }
+ } while (bIterationFromRecursion || bResumeIteration);
+ }
+}
+
+void ScFormulaCell::InterpretTail( ScInterpretTailParameter eTailParam )
+{
+ class RecursionCounter
+ {
+ ScRecursionHelper& rRec;
+ bool bStackedInIteration;
+ public:
+ RecursionCounter( ScRecursionHelper& r, ScFormulaCell* p ) : rRec(r)
+ {
+ bStackedInIteration = rRec.IsDoingIteration();
+ if (bStackedInIteration)
+ rRec.GetRecursionInIterationStack().push( p);
+ rRec.IncRecursionCount();
+ }
+ ~RecursionCounter()
+ {
+ rRec.DecRecursionCount();
+ if (bStackedInIteration)
+ rRec.GetRecursionInIterationStack().pop();
+ }
+ } aRecursionCounter( pDocument->GetRecursionHelper(), this);
+ nSeenInIteration = pDocument->GetRecursionHelper().GetIteration();
+ if( !pCode->GetCodeLen() && !pCode->GetCodeError() )
+ {
+ // #i11719# no UPN and no error and no token code but result string present
+ // => interpretation of this cell during name-compilation and unknown names
+ // => can't exchange underlying code array in CompileTokenArray() /
+ // Compile() because interpreter's token iterator would crash.
+ // This should only be a temporary condition and, since we set an
+ // error, if ran into it again we'd bump into the dirty-clearing
+ // condition further down.
+ if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
+ {
+ pCode->SetCodeError( errNoCode );
+ // This is worth an assertion; if encountered in daily work
+ // documents we might need another solution. Or just confirm correctness.
+ DBG_ERRORFILE( "ScFormulaCell::Interpret: no UPN, no error, no token, but string" );
+ return;
+ }
+ CompileTokenArray();
+ }
+
+ if( pCode->GetCodeLen() && pDocument )
+ {
+ class StackCleaner
+ {
+ ScDocument* pDoc;
+ ScInterpreter* pInt;
+ public:
+ StackCleaner( ScDocument* pD, ScInterpreter* pI )
+ : pDoc(pD), pInt(pI)
+ {}
+ ~StackCleaner()
+ {
+ delete pInt;
+ pDoc->DecInterpretLevel();
+ }
+ };
+ pDocument->IncInterpretLevel();
+ ScInterpreter* p = new ScInterpreter( this, pDocument, aPos, *pCode );
+ StackCleaner aStackCleaner( pDocument, p);
+ USHORT nOldErrCode = aResult.GetResultError();
+ if ( nSeenInIteration == 0 )
+ { // Only the first time
+ // With bChanged=FALSE, if a newly compiled cell has a result of
+ // 0.0, no change is detected and the cell will not be repainted.
+ // bChanged = FALSE;
+ aResult.SetResultError( 0 );
+ }
+
+ switch ( aResult.GetResultError() )
+ {
+ case errCircularReference : // will be determined again if so
+ aResult.SetResultError( 0 );
+ break;
+ }
+
+ BOOL bOldRunning = bRunning;
+ bRunning = TRUE;
+ p->Interpret();
+ if (pDocument->GetRecursionHelper().IsInReturn() && eTailParam != SCITP_CLOSE_ITERATION_CIRCLE)
+ {
+ if (nSeenInIteration > 0)
+ --nSeenInIteration; // retry when iteration is resumed
+ return;
+ }
+ bRunning = bOldRunning;
+
+ // Do not create a HyperLink() cell if the formula results in an error.
+ if( p->GetError() && pCode->IsHyperLink())
+ pCode->SetHyperLink(FALSE);
+
+ if( p->GetError() && p->GetError() != errCircularReference)
+ {
+ bDirty = FALSE;
+ bTableOpDirty = FALSE;
+ bChanged = TRUE;
+ }
+ if (eTailParam == SCITP_FROM_ITERATION && IsDirtyOrInTableOpDirty())
+ {
+ bool bIsValue = aResult.IsValue(); // the previous type
+ // Did it converge?
+ if ((bIsValue && p->GetResultType() == svDouble && fabs(
+ p->GetNumResult() - aResult.GetDouble()) <=
+ pDocument->GetDocOptions().GetIterEps()) ||
+ (!bIsValue && p->GetResultType() == svString &&
+ p->GetStringResult() == aResult.GetString()))
+ {
+ // A convergence in the first iteration doesn't necessarily
+ // mean that it's done, it may be because not all related cells
+ // of a circle changed their values yet. If the set really
+ // converges it will do so also during the next iteration. This
+ // fixes situations like of #i44115#. If this wasn't wanted an
+ // initial "uncalculated" value would be needed for all cells
+ // of a circular dependency => graph needed before calculation.
+ if (nSeenInIteration > 1 ||
+ pDocument->GetDocOptions().GetIterCount() == 1)
+ {
+ bDirty = FALSE;
+ bTableOpDirty = FALSE;
+ }
+ }
+ }
+
+ // New error code?
+ if( p->GetError() != nOldErrCode )
+ bChanged = TRUE;
+ // Different number format?
+ if( nFormatType != p->GetRetFormatType() )
+ {
+ nFormatType = p->GetRetFormatType();
+ bChanged = TRUE;
+ }
+ if( nFormatIndex != p->GetRetFormatIndex() )
+ {
+ nFormatIndex = p->GetRetFormatIndex();
+ bChanged = TRUE;
+ }
+
+ // In case of changes just obtain the result, no temporary and
+ // comparison needed anymore.
+ if (bChanged)
+ aResult.SetToken( p->GetResultToken() );
+ else
+ {
+ ScFormulaResult aNewResult( p->GetResultToken());
+ StackVar eOld = aResult.GetCellResultType();
+ StackVar eNew = aNewResult.GetCellResultType();
+ bChanged = (eOld != eNew ||
+ (eNew == svDouble && aResult.GetDouble() != aNewResult.GetDouble()) ||
+ (eNew == svString && aResult.GetString() != aNewResult.GetString()));
+ aResult.Assign( aNewResult);
+ }
+
+ // Precision as shown?
+ if ( aResult.IsValue() && !p->GetError()
+ && pDocument->GetDocOptions().IsCalcAsShown()
+ && nFormatType != NUMBERFORMAT_DATE
+ && nFormatType != NUMBERFORMAT_TIME
+ && nFormatType != NUMBERFORMAT_DATETIME )
+ {
+ ULONG nFormat = pDocument->GetNumberFormat( aPos );
+ if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
+ nFormat = nFormatIndex;
+ if ( (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
+ nFormat = ScGlobal::GetStandardFormat(
+ *pDocument->GetFormatTable(), nFormat, nFormatType );
+ aResult.SetDouble( pDocument->RoundValueAsShown(
+ aResult.GetDouble(), nFormat));
+ }
+ if (eTailParam == SCITP_NORMAL)
+ {
+ bDirty = FALSE;
+ bTableOpDirty = FALSE;
+ }
+ if( aResult.GetMatrix().Is() )
+ {
+ // If the formula wasn't entered as a matrix formula, live on with
+ // the upper left corner and let reference counting delete the matrix.
+ if( cMatrixFlag != MM_FORMULA && !pCode->IsHyperLink() )
+ aResult.SetToken( aResult.GetCellResultToken());
+ }
+ if ( aResult.IsValue() && !::rtl::math::isFinite( aResult.GetDouble() ) )
+ {
+ // Coded double error may occur via filter import.
+ USHORT nErr = GetDoubleErrorValue( aResult.GetDouble());
+ aResult.SetResultError( nErr);
+ bChanged = true;
+ }
+ if( bChanged )
+ {
+ SetTextWidth( TEXTWIDTH_DIRTY );
+ SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
+ }
+ if ( !pCode->IsRecalcModeAlways() )
+ pDocument->RemoveFromFormulaTree( this );
+
+ // FORCED Zellen auch sofort auf Gueltigkeit testen (evtl. Makro starten)
+
+ if ( pCode->IsRecalcModeForced() )
+ {
+ ULONG nValidation = ((const SfxUInt32Item*) pDocument->GetAttr(
+ aPos.Col(), aPos.Row(), aPos.Tab(), ATTR_VALIDDATA ))->GetValue();
+ if ( nValidation )
+ {
+ const ScValidationData* pData = pDocument->GetValidationEntry( nValidation );
+ if ( pData && !pData->IsDataValid( this, aPos ) )
+ pData->DoCalcError( this );
+ }
+ }
+
+ // Reschedule verlangsamt das ganze erheblich, nur bei Prozentaenderung ausfuehren
+ ScProgress::GetInterpretProgress()->SetStateCountDownOnPercent(
+ pDocument->GetFormulaCodeInTree() );
+ }
+ else
+ {
+ // Zelle bei Compiler-Fehlern nicht ewig auf dirty stehenlassen
+ DBG_ASSERT( pCode->GetCodeError(), "kein UPN-Code und kein Fehler ?!?!" );
+ bDirty = FALSE;
+ bTableOpDirty = FALSE;
+ }
+}
+
+
+void ScFormulaCell::SetMatColsRows( SCCOL nCols, SCROW nRows )
+{
+ ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellTokenNonConst();
+ if (pMat)
+ pMat->SetMatColsRows( nCols, nRows);
+ else if (nCols || nRows)
+ aResult.SetToken( new ScMatrixFormulaCellToken( nCols, nRows));
+}
+
+
+void ScFormulaCell::GetMatColsRows( SCCOL & nCols, SCROW & nRows ) const
+{
+ const ScMatrixFormulaCellToken* pMat = aResult.GetMatrixFormulaCellToken();
+ if (pMat)
+ pMat->GetMatColsRows( nCols, nRows);
+ else
+ {
+ nCols = 0;
+ nRows = 0;
+ }
+}
+
+
+ULONG ScFormulaCell::GetStandardFormat( SvNumberFormatter& rFormatter, ULONG nFormat ) const
+{
+ if ( nFormatIndex && (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
+ return nFormatIndex;
+ //! not ScFormulaCell::IsValue(), that could reinterpret the formula again.
+ if ( aResult.IsValue() )
+ return ScGlobal::GetStandardFormat( aResult.GetDouble(), rFormatter, nFormat, nFormatType );
+ else
+ return ScGlobal::GetStandardFormat( rFormatter, nFormat, nFormatType );
+}
+
+
+void __EXPORT ScFormulaCell::Notify( SvtBroadcaster&, const SfxHint& rHint)
+{
+ if ( !pDocument->IsInDtorClear() && !pDocument->GetHardRecalcState() )
+ {
+ const ScHint* p = PTR_CAST( ScHint, &rHint );
+ ULONG nHint = (p ? p->GetId() : 0);
+ if (nHint & (SC_HINT_DATACHANGED | SC_HINT_DYING | SC_HINT_TABLEOPDIRTY))
+ {
+ BOOL bForceTrack = FALSE;
+ if ( nHint & SC_HINT_TABLEOPDIRTY )
+ {
+ bForceTrack = !bTableOpDirty;
+ if ( !bTableOpDirty )
+ {
+ pDocument->AddTableOpFormulaCell( this );
+ bTableOpDirty = TRUE;
+ }
+ }
+ else
+ {
+ bForceTrack = !bDirty;
+ bDirty = TRUE;
+ }
+ // #35962# Don't remove from FormulaTree to put in FormulaTrack to
+ // put in FormulaTree again and again, only if necessary.
+ // Any other means except RECALCMODE_ALWAYS by which a cell could
+ // be in FormulaTree if it would notify other cells through
+ // FormulaTrack which weren't in FormulaTrack/FormulaTree before?!?
+ // #87866# Yes. The new TableOpDirty made it necessary to have a
+ // forced mode where formulas may still be in FormulaTree from
+ // TableOpDirty but have to notify dependents for normal dirty.
+ if ( (bForceTrack || !pDocument->IsInFormulaTree( this )
+ || pCode->IsRecalcModeAlways())
+ && !pDocument->IsInFormulaTrack( this ) )
+ pDocument->AppendToFormulaTrack( this );
+ }
+ }
+}
+
+void ScFormulaCell::SetDirty()
+{
+ if ( !IsInChangeTrack() )
+ {
+ if ( pDocument->GetHardRecalcState() )
+ bDirty = TRUE;
+ else
+ {
+ // Mehrfach-FormulaTracking in Load und in CompileAll
+ // nach CopyScenario und CopyBlockFromClip vermeiden.
+ // Wenn unbedingtes FormulaTracking noetig, vor SetDirty bDirty=FALSE
+ // setzen, z.B. in CompileTokenArray
+ if ( !bDirty || !pDocument->IsInFormulaTree( this ) )
+ {
+ bDirty = TRUE;
+ pDocument->AppendToFormulaTrack( this );
+ pDocument->TrackFormulas();
+ }
+ }
+ }
+}
+
+void ScFormulaCell::SetDirtyAfterLoad()
+{
+ bDirty = TRUE;
+ if ( !pDocument->GetHardRecalcState() )
+ pDocument->PutInFormulaTree( this );
+}
+
+void ScFormulaCell::SetTableOpDirty()
+{
+ if ( !IsInChangeTrack() )
+ {
+ if ( pDocument->GetHardRecalcState() )
+ bTableOpDirty = TRUE;
+ else
+ {
+ if ( !bTableOpDirty || !pDocument->IsInFormulaTree( this ) )
+ {
+ if ( !bTableOpDirty )
+ {
+ pDocument->AddTableOpFormulaCell( this );
+ bTableOpDirty = TRUE;
+ }
+ pDocument->AppendToFormulaTrack( this );
+ pDocument->TrackFormulas( SC_HINT_TABLEOPDIRTY );
+ }
+ }
+ }
+}
+
+
+BOOL ScFormulaCell::IsDirtyOrInTableOpDirty() const
+{
+ return bDirty || (bTableOpDirty && pDocument->IsInInterpreterTableOp());
+}
+
+
+void ScFormulaCell::SetErrCode( USHORT n )
+{
+ /* FIXME: check the numerous places where ScTokenArray::GetCodeError() is
+ * used whether it is solely for transport of a simple result error and get
+ * rid of that abuse. */
+ pCode->SetCodeError( n );
+ // Hard set errors are transported as result type value per convention,
+ // e.g. via clipboard. ScFormulaResult::IsValue() and
+ // ScFormulaResult::GetDouble() handle that.
+ aResult.SetResultError( n );
+}
+
+void ScFormulaCell::AddRecalcMode( ScRecalcMode nBits )
+{
+ if ( (nBits & RECALCMODE_EMASK) != RECALCMODE_NORMAL )
+ bDirty = TRUE;
+ if ( nBits & RECALCMODE_ONLOAD_ONCE )
+ { // OnLoadOnce nur zum Dirty setzen nach Filter-Import
+ nBits = (nBits & ~RECALCMODE_EMASK) | RECALCMODE_NORMAL;
+ }
+ pCode->AddRecalcMode( nBits );
+}
+
+// Dynamically create the URLField on a mouse-over action on a hyperlink() cell.
+void ScFormulaCell::GetURLResult( String& rURL, String& rCellText )
+{
+ String aCellString;
+
+ Color* pColor;
+
+ // Cell Text uses the Cell format while the URL uses
+ // the default format for the type.
+ ULONG nCellFormat = pDocument->GetNumberFormat( aPos );
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+
+ if ( (nCellFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
+ nCellFormat = GetStandardFormat( *pFormatter,nCellFormat );
+
+ ULONG nURLFormat = ScGlobal::GetStandardFormat( *pFormatter,nCellFormat, NUMBERFORMAT_NUMBER);
+
+ if ( IsValue() )
+ {
+ double fValue = GetValue();
+ pFormatter->GetOutputString( fValue, nCellFormat, rCellText, &pColor );
+ }
+ else
+ {
+ GetString( aCellString );
+ pFormatter->GetOutputString( aCellString, nCellFormat, rCellText, &pColor );
+ }
+ ScConstMatrixRef xMat( aResult.GetMatrix());
+ if (xMat)
+ {
+ ScMatValType nMatValType;
+ // determine if the matrix result is a string or value.
+ const ScMatrixValue* pMatVal = xMat->Get(0, 1, nMatValType);
+ if (pMatVal)
+ {
+ if (!ScMatrix::IsValueType( nMatValType))
+ rURL = pMatVal->GetString();
+ else
+ pFormatter->GetOutputString( pMatVal->fVal, nURLFormat, rURL, &pColor );
+ }
+ }
+
+ if(!rURL.Len())
+ {
+ if(IsValue())
+ pFormatter->GetOutputString( GetValue(), nURLFormat, rURL, &pColor );
+ else
+ pFormatter->GetOutputString( aCellString, nURLFormat, rURL, &pColor );
+ }
+}
+
+EditTextObject* ScFormulaCell::CreateURLObject()
+{
+ String aCellText;
+ String aURL;
+ GetURLResult( aURL, aCellText );
+
+ SvxURLField aUrlField( aURL, aCellText, SVXURLFORMAT_APPDEFAULT);
+ EditEngine& rEE = pDocument->GetEditEngine();
+ rEE.SetText( EMPTY_STRING );
+ rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0xFFFF, 0xFFFF ) );
+
+ return rEE.CreateTextObject();
+}
+
+// ============================================================================
+
+ScDetectiveRefIter::ScDetectiveRefIter( ScFormulaCell* pCell )
+{
+ pCode = pCell->GetCode();
+ pCode->Reset();
+ aPos = pCell->aPos;
+}
+
+BOOL lcl_ScDetectiveRefIter_SkipRef( ScToken* p )
+{
+ ScSingleRefData& rRef1 = p->GetSingleRef();
+ if ( rRef1.IsColDeleted() || rRef1.IsRowDeleted() || rRef1.IsTabDeleted()
+ || !rRef1.Valid() )
+ return TRUE;
+ if ( p->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
+ if ( rRef2.IsColDeleted() || rRef2.IsRowDeleted() || rRef2.IsTabDeleted()
+ || !rRef2.Valid() )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL ScDetectiveRefIter::GetNextRef( ScRange& rRange )
+{
+ BOOL bRet = FALSE;
+
+ ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
+ if (p)
+ p->CalcAbsIfRel( aPos );
+
+ while ( p && lcl_ScDetectiveRefIter_SkipRef( p ) )
+ {
+ p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
+ if (p)
+ p->CalcAbsIfRel( aPos );
+ }
+
+ if( p )
+ {
+ SingleDoubleRefProvider aProv( *p );
+ rRange.aStart.Set( aProv.Ref1.nCol, aProv.Ref1.nRow, aProv.Ref1.nTab );
+ rRange.aEnd.Set( aProv.Ref2.nCol, aProv.Ref2.nRow, aProv.Ref2.nTab );
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+// ============================================================================
diff --git a/sc/source/core/data/cell2.cxx b/sc/source/core/data/cell2.cxx
new file mode 100644
index 000000000000..0dffbdefa0b7
--- /dev/null
+++ b/sc/source/core/data/cell2.cxx
@@ -0,0 +1,1356 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: cell2.cxx,v $
+ * $Revision: 1.34.102.2 $
+ *
+ * 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 ---------------------------------------------------------------
+#include <vcl/mapmod.hxx>
+#include <svx/editobj.hxx>
+#include <svx/editstat.hxx>
+
+#include "cell.hxx"
+#include "compiler.hxx"
+#include "formula/errorcodes.hxx"
+#include "document.hxx"
+#include "rangenam.hxx"
+#include "rechead.hxx"
+#include "refupdat.hxx"
+#include "scmatrix.hxx"
+#include "editutil.hxx"
+#include "chgtrack.hxx"
+#include "indexmap.hxx"
+#include "externalrefmgr.hxx"
+
+using namespace formula;
+
+// STATIC DATA -----------------------------------------------------------
+
+#ifdef USE_MEMPOOL
+const USHORT nMemPoolEditCell = (0x1000 - 64) / sizeof(ScNoteCell);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScEditCell, nMemPoolEditCell, nMemPoolEditCell )
+#endif
+
+// ============================================================================
+
+ScEditCell::ScEditCell( const EditTextObject* pObject, ScDocument* pDocP,
+ const SfxItemPool* pFromPool ) :
+ ScBaseCell( CELLTYPE_EDIT ),
+ pString( NULL ),
+ pDoc( pDocP )
+{
+ SetTextObject( pObject, pFromPool );
+}
+
+ScEditCell::ScEditCell( const ScEditCell& rCell, ScDocument& rDoc ) :
+ ScBaseCell( rCell ),
+ pString( NULL ),
+ pDoc( &rDoc )
+{
+ SetTextObject( rCell.pData, rCell.pDoc->GetEditPool() );
+}
+
+ScEditCell::ScEditCell( const String& rString, ScDocument* pDocP ) :
+ ScBaseCell( CELLTYPE_EDIT ),
+ pString( NULL ),
+ pDoc( pDocP )
+{
+ DBG_ASSERT( rString.Search('\n') != STRING_NOTFOUND ||
+ rString.Search(CHAR_CR) != STRING_NOTFOUND,
+ "EditCell mit einfachem Text !?!?" );
+
+ EditEngine& rEngine = pDoc->GetEditEngine();
+ rEngine.SetText( rString );
+ pData = rEngine.CreateTextObject();
+}
+
+ScEditCell::~ScEditCell()
+{
+ delete pData;
+ delete pString;
+
+#ifdef DBG_UTIL
+ eCellType = CELLTYPE_DESTROYED;
+#endif
+}
+
+void ScEditCell::SetData( const EditTextObject* pObject,
+ const SfxItemPool* pFromPool )
+{
+ if ( pString )
+ {
+ delete pString;
+ pString = NULL;
+ }
+ delete pData;
+ SetTextObject( pObject, pFromPool );
+}
+
+void ScEditCell::GetData( const EditTextObject*& rpObject ) const
+{
+ rpObject = pData;
+}
+
+void ScEditCell::GetString( String& rString ) const
+{
+ if ( pString )
+ rString = *pString;
+ else if ( pData )
+ {
+ // auch Text von URL-Feldern, Doc-Engine ist eine ScFieldEditEngine
+ EditEngine& rEngine = pDoc->GetEditEngine();
+ rEngine.SetText( *pData );
+ rString = ScEditUtil::GetSpaceDelimitedString(rEngine); // space between paragraphs
+ // kurze Strings fuer Formeln merken
+ if ( rString.Len() < MAXSTRLEN )
+ ((ScEditCell*)this)->pString = new String( rString ); //! non-const
+ }
+ else
+ rString.Erase();
+}
+
+void ScEditCell::SetTextObject( const EditTextObject* pObject,
+ const SfxItemPool* pFromPool )
+{
+ if ( pObject )
+ {
+ if ( pFromPool && pDoc->GetEditPool() == pFromPool )
+ pData = pObject->Clone();
+ else
+ { //! anderer Pool
+ // Leider gibt es keinen anderen Weg, um den Pool umzuhaengen,
+ // als das Object durch eine entsprechende Engine zu schleusen..
+ EditEngine& rEngine = pDoc->GetEditEngine();
+ if ( pObject->HasOnlineSpellErrors() )
+ {
+ ULONG nControl = rEngine.GetControlWord();
+ const ULONG nSpellControl = EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS;
+ BOOL bNewControl = ( (nControl & nSpellControl) != nSpellControl );
+ if ( bNewControl )
+ rEngine.SetControlWord( nControl | nSpellControl );
+ rEngine.SetText( *pObject );
+ pData = rEngine.CreateTextObject();
+ if ( bNewControl )
+ rEngine.SetControlWord( nControl );
+ }
+ else
+ {
+ rEngine.SetText( *pObject );
+ pData = rEngine.CreateTextObject();
+ }
+ }
+ }
+ else
+ pData = NULL;
+}
+
+// ============================================================================
+
+BOOL ScFormulaCell::IsEmpty()
+{
+ if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
+ Interpret();
+ return aResult.GetCellResultType() == formula::svEmptyCell;
+}
+
+BOOL ScFormulaCell::IsEmptyDisplayedAsString()
+{
+ if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
+ Interpret();
+ return aResult.IsEmptyDisplayedAsString();
+}
+
+BOOL ScFormulaCell::IsValue()
+{
+ if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
+ Interpret();
+ return aResult.IsValue();
+}
+
+double ScFormulaCell::GetValue()
+{
+ if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
+ Interpret();
+ if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) &&
+ !aResult.GetResultError())
+ return aResult.GetDouble();
+ return 0.0;
+}
+
+double ScFormulaCell::GetValueAlways()
+{
+ // for goal seek: return result value even if error code is set
+
+ if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
+ Interpret();
+ return aResult.GetDouble();
+}
+
+void ScFormulaCell::GetString( String& rString )
+{
+ if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
+ Interpret();
+ if ((!pCode->GetCodeError() || pCode->GetCodeError() == errDoubleRef) &&
+ !aResult.GetResultError())
+ rString = aResult.GetString();
+ else
+ rString.Erase();
+}
+
+const ScMatrix* ScFormulaCell::GetMatrix()
+{
+ if ( pDocument->GetAutoCalc() )
+ {
+ // Was stored !bDirty but an accompanying matrix cell was bDirty?
+ // => we need to get the matrix.
+ if (!bDirty && cMatrixFlag == MM_FORMULA && !aResult.GetMatrix().Is())
+ bDirty = TRUE;
+ if ( IsDirtyOrInTableOpDirty() )
+ Interpret();
+ }
+ return aResult.GetMatrix();
+}
+
+BOOL ScFormulaCell::GetMatrixOrigin( ScAddress& rPos ) const
+{
+ switch ( cMatrixFlag )
+ {
+ case MM_FORMULA :
+ rPos = aPos;
+ return TRUE;
+// break;
+ case MM_REFERENCE :
+ {
+ pCode->Reset();
+ ScToken* t = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
+ if( t )
+ {
+ ScSingleRefData& rRef = t->GetSingleRef();
+ rRef.CalcAbsIfRel( aPos );
+ if ( rRef.Valid() )
+ {
+ rPos.Set( rRef.nCol, rRef.nRow, rRef.nTab );
+ return TRUE;
+ }
+ }
+ }
+ break;
+ }
+ return FALSE;
+}
+
+
+/*
+ Edge-Values:
+
+ 8
+ 4 16
+ 2
+
+ innerhalb: 1
+ ausserhalb: 0
+ (reserviert: offen: 32)
+ */
+
+USHORT ScFormulaCell::GetMatrixEdge( ScAddress& rOrgPos )
+{
+ switch ( cMatrixFlag )
+ {
+ case MM_FORMULA :
+ case MM_REFERENCE :
+ {
+ static SCCOL nC;
+ static SCROW nR;
+ ScAddress aOrg;
+ if ( !GetMatrixOrigin( aOrg ) )
+ return 0; // dumm gelaufen..
+ if ( aOrg != rOrgPos )
+ { // erstes Mal oder andere Matrix als letztes Mal
+ rOrgPos = aOrg;
+ ScFormulaCell* pFCell;
+ if ( cMatrixFlag == MM_REFERENCE )
+ pFCell = (ScFormulaCell*) pDocument->GetCell( aOrg );
+ else
+ pFCell = this; // this MM_FORMULA
+ // this gibt's nur einmal, kein Vergleich auf pFCell==this
+ if ( pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA
+ && pFCell->cMatrixFlag == MM_FORMULA )
+ {
+ pFCell->GetMatColsRows( nC, nR );
+ if ( nC == 0 || nR == 0 )
+ { // aus altem Dokument geladen, neu erzeugen
+ nC = 1;
+ nR = 1;
+ ScAddress aTmpOrg;
+ ScBaseCell* pCell;
+ ScAddress aAdr( aOrg );
+ aAdr.IncCol();
+ BOOL bCont = TRUE;
+ do
+ {
+ pCell = pDocument->GetCell( aAdr );
+ if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA
+ && ((ScFormulaCell*)pCell)->cMatrixFlag == MM_REFERENCE
+ && GetMatrixOrigin( aTmpOrg ) && aTmpOrg == aOrg )
+ {
+ nC++;
+ aAdr.IncCol();
+ }
+ else
+ bCont = FALSE;
+ } while ( bCont );
+ aAdr = aOrg;
+ aAdr.IncRow();
+ bCont = TRUE;
+ do
+ {
+ pCell = pDocument->GetCell( aAdr );
+ if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA
+ && ((ScFormulaCell*)pCell)->cMatrixFlag == MM_REFERENCE
+ && GetMatrixOrigin( aTmpOrg ) && aTmpOrg == aOrg )
+ {
+ nR++;
+ aAdr.IncRow();
+ }
+ else
+ bCont = FALSE;
+ } while ( bCont );
+ pFCell->SetMatColsRows( nC, nR );
+ }
+ }
+ else
+ {
+#ifndef PRODUCT
+ String aTmp;
+ ByteString aMsg( "broken Matrix, no MatFormula at origin, Pos: " );
+ aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
+ aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
+ aMsg += ", MatOrg: ";
+ aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
+ aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
+ DBG_ERRORFILE( aMsg.GetBuffer() );
+#endif
+ return 0; // bad luck ...
+ }
+ }
+ // here we are, healthy and clean, somewhere in between
+ SCsCOL dC = aPos.Col() - aOrg.Col();
+ SCsROW dR = aPos.Row() - aOrg.Row();
+ USHORT nEdges = 0;
+ if ( dC >= 0 && dR >= 0 && dC < nC && dR < nR )
+ {
+ if ( dC == 0 )
+ nEdges |= 4; // linke Kante
+ if ( dC+1 == nC )
+ nEdges |= 16; // rechte Kante
+ if ( dR == 0 )
+ nEdges |= 8; // obere Kante
+ if ( dR+1 == nR )
+ nEdges |= 2; // untere Kante
+ if ( !nEdges )
+ nEdges = 1; // mittendrin
+ }
+#ifndef PRODUCT
+ else
+ {
+ String aTmp;
+ ByteString aMsg( "broken Matrix, Pos: " );
+ aPos.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
+ aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
+ aMsg += ", MatOrg: ";
+ aOrg.Format( aTmp, SCA_VALID_COL | SCA_VALID_ROW, pDocument );
+ aMsg += ByteString( aTmp, RTL_TEXTENCODING_ASCII_US );
+ aMsg += ", MatCols: ";
+ aMsg += ByteString::CreateFromInt32( nC );
+ aMsg += ", MatRows: ";
+ aMsg += ByteString::CreateFromInt32( nR );
+ aMsg += ", DiffCols: ";
+ aMsg += ByteString::CreateFromInt32( dC );
+ aMsg += ", DiffRows: ";
+ aMsg += ByteString::CreateFromInt32( dR );
+ DBG_ERRORFILE( aMsg.GetBuffer() );
+ }
+#endif
+ return nEdges;
+// break;
+ }
+ default:
+ return 0;
+ }
+}
+
+USHORT ScFormulaCell::GetErrCode()
+{
+ if (IsDirtyOrInTableOpDirty() && pDocument->GetAutoCalc())
+ Interpret();
+ /* FIXME: If ScTokenArray::SetCodeError() was really only for code errors
+ * and not also abused for signaling other error conditions we could bail
+ * out even before attempting to interpret broken code. */
+ USHORT nErr = pCode->GetCodeError();
+ if (nErr)
+ return nErr;
+ return aResult.GetResultError();
+}
+
+USHORT ScFormulaCell::GetRawError()
+{
+ USHORT nErr = pCode->GetCodeError();
+ if (nErr)
+ return nErr;
+ return aResult.GetResultError();
+}
+
+BOOL ScFormulaCell::HasOneReference( ScRange& r ) const
+{
+ pCode->Reset();
+ ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
+ if( p && !pCode->GetNextReferenceRPN() ) // nur eine!
+ {
+ p->CalcAbsIfRel( aPos );
+ SingleDoubleRefProvider aProv( *p );
+ r.aStart.Set( aProv.Ref1.nCol,
+ aProv.Ref1.nRow,
+ aProv.Ref1.nTab );
+ r.aEnd.Set( aProv.Ref2.nCol,
+ aProv.Ref2.nRow,
+ aProv.Ref2.nTab );
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+BOOL ScFormulaCell::HasRelNameReference() const
+{
+ pCode->Reset();
+ ScToken* t;
+ while ( ( t = static_cast<ScToken*>(pCode->GetNextReferenceRPN()) ) != NULL )
+ {
+ if ( t->GetSingleRef().IsRelName() ||
+ (t->GetType() == formula::svDoubleRef &&
+ t->GetDoubleRef().Ref2.IsRelName()) )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL ScFormulaCell::HasColRowName() const
+{
+ pCode->Reset();
+ return (pCode->GetNextColRowName() != NULL);
+}
+
+void ScFormulaCell::UpdateReference(UpdateRefMode eUpdateRefMode,
+ const ScRange& r,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ ScDocument* pUndoDoc )
+{
+ SCCOL nCol1 = r.aStart.Col();
+ SCROW nRow1 = r.aStart.Row();
+ SCTAB nTab1 = r.aStart.Tab();
+ SCCOL nCol2 = r.aEnd.Col();
+ SCROW nRow2 = r.aEnd.Row();
+ SCTAB nTab2 = r.aEnd.Tab();
+ SCCOL nCol = aPos.Col();
+ SCROW nRow = aPos.Row();
+ SCTAB nTab = aPos.Tab();
+ ScAddress aUndoPos( aPos ); // position for undo cell in pUndoDoc
+ ScAddress aOldPos( aPos );
+// BOOL bPosChanged = FALSE; // ob diese Zelle bewegt wurde
+ BOOL bIsInsert = FALSE;
+ if (eUpdateRefMode == URM_INSDEL)
+ {
+ bIsInsert = (nDx >= 0 && nDy >= 0 && nDz >= 0);
+ if ( nDx && nRow >= nRow1 && nRow <= nRow2 &&
+ nTab >= nTab1 && nTab <= nTab2 )
+ {
+ if (nCol >= nCol1)
+ {
+ nCol = sal::static_int_cast<SCCOL>( nCol + nDx );
+ if ((SCsCOL) nCol < 0)
+ nCol = 0;
+ else if ( nCol > MAXCOL )
+ nCol = MAXCOL;
+ aPos.SetCol( nCol );
+// bPosChanged = TRUE;
+ }
+ }
+ if ( nDy && nCol >= nCol1 && nCol <= nCol2 &&
+ nTab >= nTab1 && nTab <= nTab2 )
+ {
+ if (nRow >= nRow1)
+ {
+ nRow = sal::static_int_cast<SCROW>( nRow + nDy );
+ if ((SCsROW) nRow < 0)
+ nRow = 0;
+ else if ( nRow > MAXROW )
+ nRow = MAXROW;
+ aPos.SetRow( nRow );
+// bPosChanged = TRUE;
+ }
+ }
+ if ( nDz && nCol >= nCol1 && nCol <= nCol2 &&
+ nRow >= nRow1 && nRow <= nRow2 )
+ {
+ if (nTab >= nTab1)
+ {
+ SCTAB nMaxTab = pDocument->GetTableCount() - 1;
+ nTab = sal::static_int_cast<SCTAB>( nTab + nDz );
+ if ((SCsTAB) nTab < 0)
+ nTab = 0;
+ else if ( nTab > nMaxTab )
+ nTab = nMaxTab;
+ aPos.SetTab( nTab );
+// bPosChanged = TRUE;
+ }
+ }
+ }
+ else if ( r.In( aPos ) )
+ {
+ aOldPos.Set( nCol - nDx, nRow - nDy, nTab - nDz );
+// bPosChanged = TRUE;
+ }
+
+ BOOL bHasRefs = FALSE;
+ BOOL bHasColRowNames = FALSE;
+ BOOL bOnRefMove = FALSE;
+ if ( !pDocument->IsClipOrUndo() )
+ {
+ pCode->Reset();
+ bHasRefs = (pCode->GetNextReferenceRPN() != NULL);
+ if ( !bHasRefs || eUpdateRefMode == URM_COPY )
+ {
+ pCode->Reset();
+ bHasColRowNames = (pCode->GetNextColRowName() != NULL);
+ bHasRefs = bHasRefs || bHasColRowNames;
+ }
+ bOnRefMove = pCode->IsRecalcModeOnRefMove();
+ }
+ if( bHasRefs || bOnRefMove )
+ {
+ ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
+ BOOL bValChanged;
+ ScRangeData* pRangeData;
+ BOOL bRangeModified; // any range, not only shared formula
+ BOOL bRefSizeChanged;
+ if ( bHasRefs )
+ {
+ ScCompiler aComp(pDocument, aPos, *pCode);
+ aComp.SetGrammar(pDocument->GetGrammar());
+ pRangeData = aComp.UpdateReference(eUpdateRefMode, aOldPos, r,
+ nDx, nDy, nDz,
+ bValChanged, bRefSizeChanged);
+ bRangeModified = aComp.HasModifiedRange();
+ }
+ else
+ {
+ bValChanged = FALSE;
+ pRangeData = NULL;
+ bRangeModified = FALSE;
+ bRefSizeChanged = FALSE;
+ }
+ if ( bOnRefMove )
+ bOnRefMove = (bValChanged || (aPos != aOldPos));
+ // Cell may reference itself, e.g. ocColumn, ocRow without parameter
+
+ BOOL bColRowNameCompile, bHasRelName, bNewListening, bInDeleteUndo;
+ if ( bHasRefs )
+ {
+ // Upon Insert ColRowNames have to be recompiled in case the
+ // insertion occurs right in front of the range.
+ bColRowNameCompile =
+ (eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0));
+ if ( bColRowNameCompile )
+ {
+ bColRowNameCompile = FALSE;
+ ScToken* t;
+ ScRangePairList* pColList = pDocument->GetColNameRanges();
+ ScRangePairList* pRowList = pDocument->GetRowNameRanges();
+ pCode->Reset();
+ while ( !bColRowNameCompile && (t = static_cast<ScToken*>(pCode->GetNextColRowName())) != NULL )
+ {
+ ScSingleRefData& rRef = t->GetSingleRef();
+ if ( nDy > 0 && rRef.IsColRel() )
+ { // ColName
+ rRef.CalcAbsIfRel( aPos );
+ ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
+ ScRangePair* pR = pColList->Find( aAdr );
+ if ( pR )
+ { // definiert
+ if ( pR->GetRange(1).aStart.Row() == nRow1 )
+ bColRowNameCompile = TRUE;
+ }
+ else
+ { // on the fly
+ if ( rRef.nRow + 1 == nRow1 )
+ bColRowNameCompile = TRUE;
+ }
+ }
+ if ( nDx > 0 && rRef.IsRowRel() )
+ { // RowName
+ rRef.CalcAbsIfRel( aPos );
+ ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
+ ScRangePair* pR = pRowList->Find( aAdr );
+ if ( pR )
+ { // definiert
+ if ( pR->GetRange(1).aStart.Col() == nCol1 )
+ bColRowNameCompile = TRUE;
+ }
+ else
+ { // on the fly
+ if ( rRef.nCol + 1 == nCol1 )
+ bColRowNameCompile = TRUE;
+ }
+ }
+ }
+ }
+ else if ( eUpdateRefMode == URM_MOVE )
+ { // bei Move/D&D neu kompilieren wenn ColRowName verschoben wurde
+ // oder diese Zelle auf einen zeigt und verschoben wurde
+ bColRowNameCompile = bCompile; // evtl. aus Copy-ctor
+ if ( !bColRowNameCompile )
+ {
+ BOOL bMoved = (aPos != aOldPos);
+ pCode->Reset();
+ ScToken* t = static_cast<ScToken*>(pCode->GetNextColRowName());
+ if ( t && bMoved )
+ bColRowNameCompile = TRUE;
+ while ( t && !bColRowNameCompile )
+ {
+ ScSingleRefData& rRef = t->GetSingleRef();
+ rRef.CalcAbsIfRel( aPos );
+ if ( rRef.Valid() )
+ {
+ ScAddress aAdr( rRef.nCol, rRef.nRow, rRef.nTab );
+ if ( r.In( aAdr ) )
+ bColRowNameCompile = TRUE;
+ }
+ t = static_cast<ScToken*>(pCode->GetNextColRowName());
+ }
+ }
+ }
+ else if ( eUpdateRefMode == URM_COPY && bHasColRowNames && bValChanged )
+ {
+ bColRowNameCompile = TRUE;
+ }
+ ScChangeTrack* pChangeTrack = pDocument->GetChangeTrack();
+ if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
+ bInDeleteUndo = TRUE;
+ else
+ bInDeleteUndo = FALSE;
+ // RelNameRefs are always moved
+ bHasRelName = HasRelNameReference();
+ // Reference changed and new listening needed?
+ // Except in Insert/Delete without specialties.
+ bNewListening = (bRangeModified || pRangeData || bColRowNameCompile
+ || (bValChanged && (eUpdateRefMode != URM_INSDEL ||
+ bInDeleteUndo || bRefSizeChanged)) ||
+ (bHasRelName && eUpdateRefMode != URM_COPY))
+ // #i36299# Don't duplicate action during cut&paste / drag&drop
+ // on a cell in the range moved, start/end listeners is done
+ // via ScDocument::DeleteArea() and ScDocument::CopyFromClip().
+ && !(eUpdateRefMode == URM_MOVE &&
+ pDocument->IsInsertingFromOtherDoc() && r.In(aPos));
+ if ( bNewListening )
+ EndListeningTo( pDocument, pOld, aOldPos );
+ }
+ else
+ {
+ bColRowNameCompile = bHasRelName = bNewListening = bInDeleteUndo =
+ FALSE;
+ }
+
+ BOOL bNeedDirty;
+ // NeedDirty bei Aenderungen ausser Copy und Move/Insert ohne RelNames
+ if ( bRangeModified || pRangeData || bColRowNameCompile ||
+ (bValChanged && eUpdateRefMode != URM_COPY &&
+ (eUpdateRefMode != URM_MOVE || bHasRelName) &&
+ (!bIsInsert || bHasRelName || bInDeleteUndo ||
+ bRefSizeChanged)) || bOnRefMove)
+ bNeedDirty = TRUE;
+ else
+ bNeedDirty = FALSE;
+ if (pUndoDoc && (bValChanged || pRangeData || bOnRefMove))
+ {
+ // Copy the cell to aUndoPos, which is its current position in the document,
+ // so this works when UpdateReference is called before moving the cells
+ // (InsertCells/DeleteCells - aPos is changed above) as well as when UpdateReference
+ // is called after moving the cells (MoveBlock/PasteFromClip - aOldPos is changed).
+
+ ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aUndoPos,
+ pOld, eTempGrammar, cMatrixFlag );
+ pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!)
+ pUndoDoc->PutCell( aUndoPos, pFCell );
+ }
+ bValChanged = FALSE;
+ if ( pRangeData )
+ { // Replace shared formula with own formula
+ pDocument->RemoveFromFormulaTree( this ); // update formula count
+ delete pCode;
+ pCode = pRangeData->GetCode()->Clone();
+ ScCompiler aComp2(pDocument, aPos, *pCode);
+ aComp2.SetGrammar(pDocument->GetGrammar());
+ aComp2.UpdateSharedFormulaReference( eUpdateRefMode, aOldPos, r,
+ nDx, nDy, nDz );
+ bValChanged = TRUE;
+ bNeedDirty = TRUE;
+ }
+ if ( ( bCompile = (bCompile || bValChanged || bRangeModified || bColRowNameCompile) ) != 0 )
+ {
+ CompileTokenArray( bNewListening ); // kein Listening
+ bNeedDirty = TRUE;
+ }
+ if ( !bInDeleteUndo )
+ { // In ChangeTrack Delete-Reject listeners are established in
+ // InsertCol/InsertRow
+ if ( bNewListening )
+ {
+ if ( eUpdateRefMode == URM_INSDEL )
+ {
+ // Inserts/Deletes re-establish listeners after all
+ // UpdateReference calls.
+ // All replaced shared formula listeners have to be
+ // established after an Insert or Delete. Do nothing here.
+ SetNeedsListening( TRUE);
+ }
+ else
+ StartListeningTo( pDocument );
+ }
+ }
+ if ( bNeedDirty && (!(eUpdateRefMode == URM_INSDEL && bHasRelName) || pRangeData) )
+ { // Referenzen abgeschnitten, ungueltig o.ae.?
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ // kein Interpret in SubMinimalRecalc wegen evtl. falscher Referenzen
+ pDocument->SetAutoCalc( FALSE );
+ SetDirty();
+ pDocument->SetAutoCalc( bOldAutoCalc );
+ }
+
+ delete pOld;
+ }
+
+ pCode->Reset();
+ for ( formula::FormulaToken* t = pCode->GetNextReferenceOrName(); t; t = pCode->GetNextReferenceOrName() )
+ {
+ StackVar sv = t->GetType();
+ if (sv == svExternalSingleRef || sv == svExternalDoubleRef || sv == svExternalName)
+ {
+ pDocument->GetExternalRefManager()->updateRefCell(aOldPos, aPos, eUpdateRefMode == URM_COPY);
+ break;
+ }
+ }
+}
+
+void ScFormulaCell::UpdateInsertTab(SCTAB nTable)
+{
+ BOOL bPosChanged = ( aPos.Tab() >= nTable ? TRUE : FALSE );
+ pCode->Reset();
+ if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
+ {
+ EndListeningTo( pDocument );
+ // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateInsertTab !
+ if ( bPosChanged )
+ aPos.IncTab();
+ ScRangeData* pRangeData;
+ ScCompiler aComp(pDocument, aPos, *pCode);
+ aComp.SetGrammar(pDocument->GetGrammar());
+ pRangeData = aComp.UpdateInsertTab( nTable, FALSE );
+ if (pRangeData) // Shared Formula gegen echte Formel
+ { // austauschen
+ BOOL bRefChanged;
+ pDocument->RemoveFromFormulaTree( this ); // update formula count
+ delete pCode;
+ pCode = new ScTokenArray( *pRangeData->GetCode() );
+ ScCompiler aComp2(pDocument, aPos, *pCode);
+ aComp2.SetGrammar(pDocument->GetGrammar());
+ aComp2.MoveRelWrap();
+ aComp2.UpdateInsertTab( nTable, FALSE );
+ // If the shared formula contained a named range/formula containing
+ // an absolute reference to a sheet, those have to be readjusted.
+ aComp2.UpdateDeleteTab( nTable, FALSE, TRUE, bRefChanged );
+ bCompile = TRUE;
+ }
+ // kein StartListeningTo weil pTab[nTab] noch nicht existiert!
+ }
+ else if ( bPosChanged )
+ aPos.IncTab();
+}
+
+BOOL ScFormulaCell::UpdateDeleteTab(SCTAB nTable, BOOL bIsMove)
+{
+ BOOL bRefChanged = FALSE;
+ BOOL bPosChanged = ( aPos.Tab() > nTable ? TRUE : FALSE );
+ pCode->Reset();
+ if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
+ {
+ EndListeningTo( pDocument );
+ // IncTab _nach_ EndListeningTo und _vor_ Compiler UpdateDeleteTab !
+ if ( bPosChanged )
+ aPos.IncTab(-1);
+ ScRangeData* pRangeData;
+ ScCompiler aComp(pDocument, aPos, *pCode);
+ aComp.SetGrammar(pDocument->GetGrammar());
+ pRangeData = aComp.UpdateDeleteTab(nTable, bIsMove, FALSE, bRefChanged);
+ if (pRangeData) // Shared Formula gegen echte Formel
+ { // austauschen
+ pDocument->RemoveFromFormulaTree( this ); // update formula count
+ delete pCode;
+ pCode = pRangeData->GetCode()->Clone();
+ ScCompiler aComp2(pDocument, aPos, *pCode);
+ aComp2.SetGrammar(pDocument->GetGrammar());
+ aComp2.CompileTokenArray();
+ aComp2.MoveRelWrap();
+ aComp2.UpdateDeleteTab( nTable, FALSE, FALSE, bRefChanged );
+ // If the shared formula contained a named range/formula containing
+ // an absolute reference to a sheet, those have to be readjusted.
+ aComp2.UpdateInsertTab( nTable,TRUE );
+ // bRefChanged kann beim letzten UpdateDeleteTab zurueckgesetzt worden sein
+ bRefChanged = TRUE;
+ bCompile = TRUE;
+ }
+ // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
+ }
+ else if ( bPosChanged )
+ aPos.IncTab(-1);
+
+ return bRefChanged;
+}
+
+void ScFormulaCell::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
+{
+ pCode->Reset();
+ if( pCode->GetNextReferenceRPN() && !pDocument->IsClipOrUndo() )
+ {
+ EndListeningTo( pDocument );
+ // SetTab _nach_ EndListeningTo und _vor_ Compiler UpdateMoveTab !
+ aPos.SetTab( nTabNo );
+ ScRangeData* pRangeData;
+ ScCompiler aComp(pDocument, aPos, *pCode);
+ aComp.SetGrammar(pDocument->GetGrammar());
+ pRangeData = aComp.UpdateMoveTab( nOldPos, nNewPos, FALSE );
+ if (pRangeData) // Shared Formula gegen echte Formel
+ { // austauschen
+ pDocument->RemoveFromFormulaTree( this ); // update formula count
+ delete pCode;
+ pCode = pRangeData->GetCode()->Clone();
+ ScCompiler aComp2(pDocument, aPos, *pCode);
+ aComp2.SetGrammar(pDocument->GetGrammar());
+ aComp2.CompileTokenArray();
+ aComp2.MoveRelWrap();
+ aComp2.UpdateMoveTab( nOldPos, nNewPos, TRUE );
+ bCompile = TRUE;
+ }
+ // kein StartListeningTo weil pTab[nTab] noch nicht korrekt!
+ }
+ else
+ aPos.SetTab( nTabNo );
+}
+
+void ScFormulaCell::UpdateInsertTabAbs(SCTAB nTable)
+{
+ if( !pDocument->IsClipOrUndo() )
+ {
+ pCode->Reset();
+ ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
+ while( p )
+ {
+ ScSingleRefData& rRef1 = p->GetSingleRef();
+ if( !rRef1.IsTabRel() && (SCsTAB) nTable <= rRef1.nTab )
+ rRef1.nTab++;
+ if( p->GetType() == formula::svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
+ if( !rRef2.IsTabRel() && (SCsTAB) nTable <= rRef2.nTab )
+ rRef2.nTab++;
+ }
+ p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
+ }
+ }
+}
+
+BOOL ScFormulaCell::TestTabRefAbs(SCTAB nTable)
+{
+ BOOL bRet = FALSE;
+ if( !pDocument->IsClipOrUndo() )
+ {
+ pCode->Reset();
+ ScToken* p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
+ while( p )
+ {
+ ScSingleRefData& rRef1 = p->GetSingleRef();
+ if( !rRef1.IsTabRel() )
+ {
+ if( (SCsTAB) nTable != rRef1.nTab )
+ bRet = TRUE;
+ else if (nTable != aPos.Tab())
+ rRef1.nTab = aPos.Tab();
+ }
+ if( p->GetType() == formula::svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
+ if( !rRef2.IsTabRel() )
+ {
+ if( (SCsTAB) nTable != rRef2.nTab )
+ bRet = TRUE;
+ else if (nTable != aPos.Tab())
+ rRef2.nTab = aPos.Tab();
+ }
+ }
+ p = static_cast<ScToken*>(pCode->GetNextReferenceRPN());
+ }
+ }
+ return bRet;
+}
+
+void ScFormulaCell::UpdateCompile( BOOL bForceIfNameInUse )
+{
+ if ( bForceIfNameInUse && !bCompile )
+ bCompile = pCode->HasNameOrColRowName();
+ if ( bCompile )
+ pCode->SetCodeError( 0 ); // make sure it will really be compiled
+ CompileTokenArray();
+}
+
+// Referenzen transponieren - wird nur in Clipboard-Dokumenten aufgerufen
+
+void ScFormulaCell::TransposeReference()
+{
+ BOOL bFound = FALSE;
+ pCode->Reset();
+ ScToken* t;
+ while ( ( t = static_cast<ScToken*>(pCode->GetNextReference()) ) != NULL )
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( rRef1.IsColRel() && rRef1.IsRowRel() )
+ {
+ BOOL bDouble = (t->GetType() == formula::svDoubleRef);
+ ScSingleRefData& rRef2 = (bDouble ? t->GetDoubleRef().Ref2 : rRef1);
+ if ( !bDouble || (rRef2.IsColRel() && rRef2.IsRowRel()) )
+ {
+ INT16 nTemp;
+
+ nTemp = rRef1.nRelCol;
+ rRef1.nRelCol = static_cast<SCCOL>(rRef1.nRelRow);
+ rRef1.nRelRow = static_cast<SCROW>(nTemp);
+
+ if ( bDouble )
+ {
+ nTemp = rRef2.nRelCol;
+ rRef2.nRelCol = static_cast<SCCOL>(rRef2.nRelRow);
+ rRef2.nRelRow = static_cast<SCROW>(nTemp);
+ }
+
+ bFound = TRUE;
+ }
+ }
+ }
+
+ if (bFound)
+ bCompile = TRUE;
+}
+
+void ScFormulaCell::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
+ ScDocument* pUndoDoc )
+{
+ EndListeningTo( pDocument );
+
+ ScAddress aOldPos = aPos;
+ BOOL bPosChanged = FALSE; // ob diese Zelle bewegt wurde
+
+ ScRange aDestRange( rDest, ScAddress(
+ static_cast<SCCOL>(rDest.Col() + rSource.aEnd.Row() - rSource.aStart.Row()),
+ static_cast<SCROW>(rDest.Row() + rSource.aEnd.Col() - rSource.aStart.Col()),
+ rDest.Tab() + rSource.aEnd.Tab() - rSource.aStart.Tab() ) );
+ if ( aDestRange.In( aOldPos ) )
+ {
+ // Position zurueckrechnen
+ SCsCOL nRelPosX = aOldPos.Col();
+ SCsROW nRelPosY = aOldPos.Row();
+ SCsTAB nRelPosZ = aOldPos.Tab();
+ ScRefUpdate::DoTranspose( nRelPosX, nRelPosY, nRelPosZ, pDocument, aDestRange, rSource.aStart );
+ aOldPos.Set( nRelPosX, nRelPosY, nRelPosZ );
+ bPosChanged = TRUE;
+ }
+
+ ScTokenArray* pOld = pUndoDoc ? pCode->Clone() : NULL;
+ BOOL bRefChanged = FALSE;
+ ScToken* t;
+
+ ScRangeData* pShared = NULL;
+ pCode->Reset();
+ while( (t = static_cast<ScToken*>(pCode->GetNextReferenceOrName())) != NULL )
+ {
+ if( t->GetOpCode() == ocName )
+ {
+ ScRangeData* pName = pDocument->GetRangeName()->FindIndex( t->GetIndex() );
+ if (pName)
+ {
+ if (pName->IsModified())
+ bRefChanged = TRUE;
+ if (pName->HasType(RT_SHAREDMOD))
+ pShared = pName;
+ }
+ }
+ else if( t->GetType() != svIndex )
+ {
+ t->CalcAbsIfRel( aOldPos );
+ BOOL bMod;
+ { // own scope for SingleDoubleRefModifier dtor if SingleRef
+ SingleDoubleRefModifier aMod( *t );
+ ScComplexRefData& rRef = aMod.Ref();
+ bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource,
+ rDest, rRef ) != UR_NOTHING || bPosChanged);
+ }
+ if ( bMod )
+ {
+ t->CalcRelFromAbs( aPos );
+ bRefChanged = TRUE;
+ }
+ }
+ }
+
+ if (pShared) // Shared Formula gegen echte Formel austauschen
+ {
+ pDocument->RemoveFromFormulaTree( this ); // update formula count
+ delete pCode;
+ pCode = new ScTokenArray( *pShared->GetCode() );
+ bRefChanged = TRUE;
+ pCode->Reset();
+ while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
+ {
+ if( t->GetType() != svIndex )
+ {
+ t->CalcAbsIfRel( aOldPos );
+ BOOL bMod;
+ { // own scope for SingleDoubleRefModifier dtor if SingleRef
+ SingleDoubleRefModifier aMod( *t );
+ ScComplexRefData& rRef = aMod.Ref();
+ bMod = (ScRefUpdate::UpdateTranspose( pDocument, rSource,
+ rDest, rRef ) != UR_NOTHING || bPosChanged);
+ }
+ if ( bMod )
+ t->CalcRelFromAbs( aPos );
+ }
+ }
+ }
+
+ if (bRefChanged)
+ {
+ if (pUndoDoc)
+ {
+ ScFormulaCell* pFCell = new ScFormulaCell( pUndoDoc, aPos, pOld,
+ eTempGrammar, cMatrixFlag);
+ pFCell->aResult.SetToken( NULL); // to recognize it as changed later (Cut/Paste!)
+ pUndoDoc->PutCell( aPos.Col(), aPos.Row(), aPos.Tab(), pFCell );
+ }
+
+ bCompile = TRUE;
+ CompileTokenArray(); // ruft auch StartListeningTo
+ SetDirty();
+ }
+ else
+ StartListeningTo( pDocument ); // Listener wie vorher
+
+ delete pOld;
+}
+
+void ScFormulaCell::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
+{
+ EndListeningTo( pDocument );
+
+ BOOL bRefChanged = FALSE;
+ ScToken* t;
+ ScRangeData* pShared = NULL;
+
+ pCode->Reset();
+ while( (t = static_cast<ScToken*>(pCode->GetNextReferenceOrName())) != NULL )
+ {
+ if( t->GetOpCode() == ocName )
+ {
+ ScRangeData* pName = pDocument->GetRangeName()->FindIndex( t->GetIndex() );
+ if (pName)
+ {
+ if (pName->IsModified())
+ bRefChanged = TRUE;
+ if (pName->HasType(RT_SHAREDMOD))
+ pShared = pName;
+ }
+ }
+ else if( t->GetType() != svIndex )
+ {
+ t->CalcAbsIfRel( aPos );
+ BOOL bMod;
+ { // own scope for SingleDoubleRefModifier dtor if SingleRef
+ SingleDoubleRefModifier aMod( *t );
+ ScComplexRefData& rRef = aMod.Ref();
+ bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY,
+ rRef ) != UR_NOTHING);
+ }
+ if ( bMod )
+ {
+ t->CalcRelFromAbs( aPos );
+ bRefChanged = TRUE;
+ }
+ }
+ }
+
+ if (pShared) // Shared Formula gegen echte Formel austauschen
+ {
+ pDocument->RemoveFromFormulaTree( this ); // update formula count
+ delete pCode;
+ pCode = new ScTokenArray( *pShared->GetCode() );
+ bRefChanged = TRUE;
+ pCode->Reset();
+ while( (t = static_cast<ScToken*>(pCode->GetNextReference())) != NULL )
+ {
+ if( t->GetType() != svIndex )
+ {
+ t->CalcAbsIfRel( aPos );
+ BOOL bMod;
+ { // own scope for SingleDoubleRefModifier dtor if SingleRef
+ SingleDoubleRefModifier aMod( *t );
+ ScComplexRefData& rRef = aMod.Ref();
+ bMod = (ScRefUpdate::UpdateGrow( rArea,nGrowX,nGrowY,
+ rRef ) != UR_NOTHING);
+ }
+ if ( bMod )
+ t->CalcRelFromAbs( aPos );
+ }
+ }
+ }
+
+ if (bRefChanged)
+ {
+ bCompile = TRUE;
+ CompileTokenArray(); // ruft auch StartListeningTo
+ SetDirty();
+ }
+ else
+ StartListeningTo( pDocument ); // Listener wie vorher
+}
+
+BOOL lcl_IsRangeNameInUse(USHORT nIndex, ScTokenArray* pCode, ScRangeName* pNames)
+{
+ for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
+ {
+ if (p->GetOpCode() == ocName)
+ {
+ if (p->GetIndex() == nIndex)
+ return TRUE;
+ else
+ {
+ // RangeData kann Null sein in bestimmten Excel-Dateien (#31168#)
+ ScRangeData* pSubName = pNames->FindIndex(p->GetIndex());
+ if (pSubName && lcl_IsRangeNameInUse(nIndex,
+ pSubName->GetCode(), pNames))
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+BOOL ScFormulaCell::IsRangeNameInUse(USHORT nIndex) const
+{
+ return lcl_IsRangeNameInUse( nIndex, pCode, pDocument->GetRangeName() );
+}
+
+void lcl_FindRangeNamesInUse(std::set<USHORT>& rIndexes, ScTokenArray* pCode, ScRangeName* pNames)
+{
+ for (FormulaToken* p = pCode->First(); p; p = pCode->Next())
+ {
+ if (p->GetOpCode() == ocName)
+ {
+ USHORT nTokenIndex = p->GetIndex();
+ rIndexes.insert( nTokenIndex );
+
+ ScRangeData* pSubName = pNames->FindIndex(p->GetIndex());
+ if (pSubName)
+ lcl_FindRangeNamesInUse(rIndexes, pSubName->GetCode(), pNames);
+ }
+ }
+}
+
+void ScFormulaCell::FindRangeNamesInUse(std::set<USHORT>& rIndexes) const
+{
+ lcl_FindRangeNamesInUse( rIndexes, pCode, pDocument->GetRangeName() );
+}
+
+void ScFormulaCell::ReplaceRangeNamesInUse( const ScIndexMap& rMap )
+{
+ for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
+ {
+ if( p->GetOpCode() == ocName )
+ {
+ USHORT nIndex = p->GetIndex();
+ USHORT nNewIndex = rMap.Find( nIndex );
+ if ( nIndex != nNewIndex )
+ {
+ p->SetIndex( nNewIndex );
+ bCompile = TRUE;
+ }
+ }
+ }
+ if( bCompile )
+ CompileTokenArray();
+}
+
+void ScFormulaCell::CompileDBFormula()
+{
+ for( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
+ {
+ if ( p->GetOpCode() == ocDBArea
+ || (p->GetOpCode() == ocName && p->GetIndex() >= SC_START_INDEX_DB_COLL) )
+ {
+ bCompile = TRUE;
+ CompileTokenArray();
+ SetDirty();
+ break;
+ }
+ }
+}
+
+void ScFormulaCell::CompileDBFormula( BOOL bCreateFormulaString )
+{
+ // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
+ // 1. FormelString mit alten Namen erzeugen
+ // 2. FormelString mit neuen Namen kompilieren
+ if ( bCreateFormulaString )
+ {
+ BOOL bRecompile = FALSE;
+ pCode->Reset();
+ for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
+ {
+ switch ( p->GetOpCode() )
+ {
+ case ocBad: // DB-Bereich evtl. zugefuegt
+ case ocColRowName: // #36762# falls Namensgleichheit
+ case ocDBArea: // DB-Bereich
+ bRecompile = TRUE;
+ break;
+ case ocName:
+ if ( p->GetIndex() >= SC_START_INDEX_DB_COLL )
+ bRecompile = TRUE; // DB-Bereich
+ break;
+ default:
+ ; // nothing
+ }
+ }
+ if ( bRecompile )
+ {
+ String aFormula;
+ GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
+ if ( GetMatrixFlag() != MM_NONE && aFormula.Len() )
+ {
+ if ( aFormula.GetChar( aFormula.Len()-1 ) == '}' )
+ aFormula.Erase( aFormula.Len()-1 , 1 );
+ if ( aFormula.GetChar(0) == '{' )
+ aFormula.Erase( 0, 1 );
+ }
+ EndListeningTo( pDocument );
+ pDocument->RemoveFromFormulaTree( this );
+ pCode->Clear();
+ SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
+ }
+ }
+ else if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
+ {
+ Compile( aResult.GetHybridFormula(), FALSE, eTempGrammar );
+ aResult.SetToken( NULL);
+ SetDirty();
+ }
+}
+
+void ScFormulaCell::CompileNameFormula( BOOL bCreateFormulaString )
+{
+ // zwei Phasen, muessen (!) nacheinander aufgerufen werden:
+ // 1. FormelString mit alten RangeNames erzeugen
+ // 2. FormelString mit neuen RangeNames kompilieren
+ if ( bCreateFormulaString )
+ {
+ BOOL bRecompile = FALSE;
+ pCode->Reset();
+ for ( FormulaToken* p = pCode->First(); p && !bRecompile; p = pCode->Next() )
+ {
+ switch ( p->GetOpCode() )
+ {
+ case ocBad: // RangeName evtl. zugefuegt
+ case ocColRowName: // #36762# falls Namensgleichheit
+ bRecompile = TRUE;
+ break;
+ default:
+ if ( p->GetType() == svIndex )
+ bRecompile = TRUE; // RangeName
+ }
+ }
+ if ( bRecompile )
+ {
+ String aFormula;
+ GetFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
+ if ( GetMatrixFlag() != MM_NONE && aFormula.Len() )
+ {
+ if ( aFormula.GetChar( aFormula.Len()-1 ) == '}' )
+ aFormula.Erase( aFormula.Len()-1 , 1 );
+ if ( aFormula.GetChar(0) == '{' )
+ aFormula.Erase( 0, 1 );
+ }
+ EndListeningTo( pDocument );
+ pDocument->RemoveFromFormulaTree( this );
+ pCode->Clear();
+ SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE);
+ }
+ }
+ else if ( !pCode->GetLen() && aResult.GetHybridFormula().Len() )
+ {
+ Compile( aResult.GetHybridFormula(), FALSE, eTempGrammar );
+ aResult.SetToken( NULL);
+ SetDirty();
+ }
+}
+
+void ScFormulaCell::CompileColRowNameFormula()
+{
+ pCode->Reset();
+ for ( FormulaToken* p = pCode->First(); p; p = pCode->Next() )
+ {
+ if ( p->GetOpCode() == ocColRowName )
+ {
+ bCompile = TRUE;
+ CompileTokenArray();
+ SetDirty();
+ break;
+ }
+ }
+}
+
+// ============================================================================
+
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
new file mode 100644
index 000000000000..68d378994c14
--- /dev/null
+++ b/sc/source/core/data/column.cxx
@@ -0,0 +1,2186 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: column.cxx,v $
+ * $Revision: 1.31.128.9 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <map>
+
+#include <svtools/poolcach.hxx>
+#include <svtools/zforlist.hxx>
+#include <svx/scripttypeitem.hxx>
+#include <string.h>
+
+#include "scitems.hxx"
+#include "column.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "docpool.hxx"
+#include "attarray.hxx"
+#include "patattr.hxx"
+#include "compiler.hxx"
+#include "brdcst.hxx"
+#include "markdata.hxx"
+#include "detfunc.hxx" // for Notes in Sort/Swap
+#include "postit.hxx"
+
+//#pragma optimize ( "", off )
+// nur Search ohne Optimierung!
+
+// STATIC DATA -----------------------------------------------------------
+using namespace formula;
+
+inline BOOL IsAmbiguousScriptNonZero( BYTE nScript )
+{
+ //! move to a header file
+ return ( nScript != SCRIPTTYPE_LATIN &&
+ nScript != SCRIPTTYPE_ASIAN &&
+ nScript != SCRIPTTYPE_COMPLEX &&
+ nScript != 0 );
+}
+
+// -----------------------------------------------------------------------------------------
+
+
+ScColumn::ScColumn() :
+ nCol( 0 ),
+ nCount( 0 ),
+ nLimit( 0 ),
+ pItems( NULL ),
+ pAttrArray( NULL ),
+ pDocument( NULL )
+{
+}
+
+
+ScColumn::~ScColumn()
+{
+ FreeAll();
+ if (pAttrArray) delete pAttrArray;
+}
+
+
+void ScColumn::Init(SCCOL nNewCol, SCTAB nNewTab, ScDocument* pDoc)
+{
+ nCol = nNewCol;
+ nTab = nNewTab;
+ pDocument = pDoc;
+ pAttrArray = new ScAttrArray( nCol, nTab, pDocument );
+}
+
+
+SCsROW ScColumn::GetNextUnprotected( SCROW nRow, BOOL bUp ) const
+{
+ return pAttrArray->GetNextUnprotected(nRow, bUp);
+}
+
+
+USHORT ScColumn::GetBlockMatrixEdges( SCROW nRow1, SCROW nRow2, USHORT nMask ) const
+{
+ // nix:0, mitte:1, unten:2, links:4, oben:8, rechts:16, offen:32
+ if ( !pItems )
+ return 0;
+ if ( nRow1 == nRow2 )
+ {
+ SCSIZE nIndex;
+ if ( Search( nRow1, nIndex ) )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA
+ && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
+ {
+ ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
+ return ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
+ }
+ }
+ return 0;
+ }
+ else
+ {
+ ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
+ BOOL bOpen = FALSE;
+ USHORT nEdges = 0;
+ SCSIZE nIndex;
+ Search( nRow1, nIndex );
+ while ( nIndex < nCount && pItems[nIndex].nRow <= nRow2 )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA
+ && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
+ {
+ nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
+ if ( nEdges )
+ {
+ if ( nEdges & 8 )
+ bOpen = TRUE; // obere Kante oeffnet, weitersehen
+ else if ( !bOpen )
+ return nEdges | 32; // es gibt was, was nicht geoeffnet wurde
+ else if ( nEdges & 1 )
+ return nEdges; // mittendrin
+ // (nMask & 16 und (4 und nicht 16)) oder
+ // (nMask & 4 und (16 und nicht 4))
+ if ( ((nMask & 16) && (nEdges & 4) && !(nEdges & 16))
+ || ((nMask & 4) && (nEdges & 16) && !(nEdges & 4)) )
+ return nEdges; // nur linke/rechte Kante
+ if ( nEdges & 2 )
+ bOpen = FALSE; // untere Kante schliesst
+ }
+ }
+ nIndex++;
+ }
+ if ( bOpen )
+ nEdges |= 32; // es geht noch weiter
+ return nEdges;
+ }
+}
+
+
+BOOL ScColumn::HasSelectionMatrixFragment(const ScMarkData& rMark) const
+{
+ if ( rMark.IsMultiMarked() )
+ {
+ BOOL bFound = FALSE;
+
+ ScAddress aOrg( ScAddress::INITIALIZE_INVALID );
+ ScAddress aCurOrg( ScAddress::INITIALIZE_INVALID );
+ SCROW nTop, nBottom;
+ ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
+ while ( !bFound && aMarkIter.Next( nTop, nBottom ) )
+ {
+ BOOL bOpen = FALSE;
+ USHORT nEdges;
+ SCSIZE nIndex;
+ Search( nTop, nIndex );
+ while ( !bFound && nIndex < nCount && pItems[nIndex].nRow <= nBottom )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA
+ && ((ScFormulaCell*)pCell)->GetMatrixFlag() )
+ {
+ nEdges = ((ScFormulaCell*)pCell)->GetMatrixEdge( aOrg );
+ if ( nEdges )
+ {
+ if ( nEdges & 8 )
+ bOpen = TRUE; // obere Kante oeffnet, weitersehen
+ else if ( !bOpen )
+ return TRUE; // es gibt was, was nicht geoeffnet wurde
+ else if ( nEdges & 1 )
+ bFound = TRUE; // mittendrin, alles selektiert?
+ // (4 und nicht 16) oder (16 und nicht 4)
+ if ( (((nEdges & 4) | 16) ^ ((nEdges & 16) | 4)) )
+ bFound = TRUE; // nur linke/rechte Kante, alles selektiert?
+ if ( nEdges & 2 )
+ bOpen = FALSE; // untere Kante schliesst
+
+ if ( bFound )
+ { // alles selektiert?
+ if ( aCurOrg != aOrg )
+ { // neue Matrix zu pruefen?
+ aCurOrg = aOrg;
+ ScFormulaCell* pFCell;
+ if ( ((ScFormulaCell*)pCell)->GetMatrixFlag()
+ == MM_REFERENCE )
+ pFCell = (ScFormulaCell*) pDocument->GetCell( aOrg );
+ else
+ pFCell = (ScFormulaCell*)pCell;
+ SCCOL nC;
+ SCROW nR;
+ pFCell->GetMatColsRows( nC, nR );
+ ScRange aRange( aOrg, ScAddress(
+ aOrg.Col() + nC - 1, aOrg.Row() + nR - 1,
+ aOrg.Tab() ) );
+ if ( rMark.IsAllMarked( aRange ) )
+ bFound = FALSE;
+ }
+ else
+ bFound = FALSE; // war schon
+ }
+ }
+ }
+ nIndex++;
+ }
+ if ( bOpen )
+ return TRUE;
+ }
+ return bFound;
+ }
+ else
+ return FALSE;
+}
+
+
+BOOL ScColumn::HasLines( SCROW nRow1, SCROW nRow2, Rectangle& rSizes,
+ BOOL bLeft, BOOL bRight ) const
+{
+ return pAttrArray->HasLines( nRow1, nRow2, rSizes, bLeft, bRight );
+}
+
+
+BOOL ScColumn::HasAttrib( SCROW nRow1, SCROW nRow2, USHORT nMask ) const
+{
+ return pAttrArray->HasAttrib( nRow1, nRow2, nMask );
+}
+
+
+BOOL ScColumn::HasAttribSelection( const ScMarkData& rMark, USHORT nMask ) const
+{
+ BOOL bFound = FALSE;
+
+ SCROW nTop;
+ SCROW nBottom;
+
+ if (rMark.IsMultiMarked())
+ {
+ ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
+ while (aMarkIter.Next( nTop, nBottom ) && !bFound)
+ {
+ if (pAttrArray->HasAttrib( nTop, nBottom, nMask ))
+ bFound = TRUE;
+ }
+ }
+
+ return bFound;
+}
+
+
+BOOL ScColumn::ExtendMerge( SCCOL nThisCol, SCROW nStartRow, SCROW nEndRow,
+ SCCOL& rPaintCol, SCROW& rPaintRow,
+ BOOL bRefresh, BOOL bAttrs )
+{
+ return pAttrArray->ExtendMerge( nThisCol, nStartRow, nEndRow, rPaintCol, rPaintRow, bRefresh, bAttrs );
+}
+
+
+void ScColumn::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, BOOL bDeep ) const
+{
+ SCROW nTop;
+ SCROW nBottom;
+
+ if ( rMark.IsMultiMarked() )
+ {
+ const ScMarkArray* pArray = rMark.GetArray() + nCol;
+ if ( pArray->HasMarks() )
+ {
+ ScMarkArrayIter aMarkIter( pArray );
+ while (aMarkIter.Next( nTop, nBottom ))
+ pAttrArray->MergePatternArea( nTop, nBottom, rState, bDeep );
+ }
+ }
+}
+
+
+void ScColumn::MergePatternArea( ScMergePatternState& rState, SCROW nRow1, SCROW nRow2, BOOL bDeep ) const
+{
+ pAttrArray->MergePatternArea( nRow1, nRow2, rState, bDeep );
+}
+
+
+void ScColumn::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner,
+ ScLineFlags& rFlags,
+ SCROW nStartRow, SCROW nEndRow, BOOL bLeft, SCCOL nDistRight ) const
+{
+ pAttrArray->MergeBlockFrame( pLineOuter, pLineInner, rFlags, nStartRow, nEndRow, bLeft, nDistRight );
+}
+
+
+void ScColumn::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
+ SCROW nStartRow, SCROW nEndRow, BOOL bLeft, SCCOL nDistRight )
+{
+ pAttrArray->ApplyBlockFrame( pLineOuter, pLineInner, nStartRow, nEndRow, bLeft, nDistRight );
+}
+
+
+const ScPatternAttr* ScColumn::GetPattern( SCROW nRow ) const
+{
+ return pAttrArray->GetPattern( nRow );
+}
+
+
+const SfxPoolItem* ScColumn::GetAttr( SCROW nRow, USHORT nWhich ) const
+{
+ return &pAttrArray->GetPattern( nRow )->GetItemSet().Get(nWhich);
+}
+
+
+const ScPatternAttr* ScColumn::GetMostUsedPattern( SCROW nStartRow, SCROW nEndRow ) const
+{
+ ::std::map< const ScPatternAttr*, size_t > aAttrMap;
+ const ScPatternAttr* pMaxPattern = 0;
+ size_t nMaxCount = 0;
+
+ ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
+ const ScPatternAttr* pPattern;
+ SCROW nAttrRow1 = 0, nAttrRow2 = 0;
+
+ while( (pPattern = aAttrIter.Next( nAttrRow1, nAttrRow2 )) != 0 )
+ {
+ size_t& rnCount = aAttrMap[ pPattern ];
+ rnCount += (nAttrRow2 - nAttrRow1 + 1);
+ if( rnCount > nMaxCount )
+ {
+ pMaxPattern = pPattern;
+ nMaxCount = rnCount;
+ }
+ }
+
+ return pMaxPattern;
+}
+
+
+ULONG ScColumn::GetNumberFormat( SCROW nRow ) const
+{
+ return pAttrArray->GetPattern( nRow )->GetNumberFormat( pDocument->GetFormatTable() );
+}
+
+
+SCsROW ScColumn::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark )
+{
+ SCROW nTop = 0;
+ SCROW nBottom = 0;
+ BOOL bFound = FALSE;
+
+ if ( rMark.IsMultiMarked() )
+ {
+ ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
+ while (aMarkIter.Next( nTop, nBottom ))
+ {
+ pAttrArray->ApplyCacheArea( nTop, nBottom, pCache );
+ bFound = TRUE;
+ }
+ }
+
+ if (!bFound)
+ return -1;
+ else if (nTop==0 && nBottom==MAXROW)
+ return 0;
+ else
+ return nBottom;
+}
+
+
+void ScColumn::ChangeSelectionIndent( BOOL bIncrement, const ScMarkData& rMark )
+{
+ SCROW nTop;
+ SCROW nBottom;
+
+ if ( pAttrArray && rMark.IsMultiMarked() )
+ {
+ ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
+ while (aMarkIter.Next( nTop, nBottom ))
+ pAttrArray->ChangeIndent(nTop, nBottom, bIncrement);
+ }
+}
+
+
+void ScColumn::ClearSelectionItems( const USHORT* pWhich,const ScMarkData& rMark )
+{
+ SCROW nTop;
+ SCROW nBottom;
+
+ if ( pAttrArray && rMark.IsMultiMarked() )
+ {
+ ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
+ while (aMarkIter.Next( nTop, nBottom ))
+ pAttrArray->ClearItems(nTop, nBottom, pWhich);
+ }
+}
+
+
+void ScColumn::DeleteSelection( USHORT nDelFlag, const ScMarkData& rMark )
+{
+ SCROW nTop;
+ SCROW nBottom;
+
+ if ( rMark.IsMultiMarked() )
+ {
+ ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
+ while (aMarkIter.Next( nTop, nBottom ))
+ DeleteArea(nTop, nBottom, nDelFlag);
+ }
+}
+
+
+void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )
+{
+ const SfxItemSet* pSet = &rPatAttr.GetItemSet();
+ SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
+
+ const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
+
+ // TRUE = alten Eintrag behalten
+
+ ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, TRUE );
+ ScDocumentPool::CheckRef( *pPattern );
+ ScDocumentPool::CheckRef( *pNewPattern );
+
+ if (pNewPattern != pPattern)
+ pAttrArray->SetPattern( nRow, pNewPattern );
+}
+
+
+void ScColumn::ApplyPatternArea( SCROW nStartRow, SCROW nEndRow, const ScPatternAttr& rPatAttr )
+{
+ const SfxItemSet* pSet = &rPatAttr.GetItemSet();
+ SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
+ pAttrArray->ApplyCacheArea( nStartRow, nEndRow, &aCache );
+}
+
+
+void ScColumn::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
+ const ScPatternAttr& rPattern, short nNewType )
+{
+ const SfxItemSet* pSet = &rPattern.GetItemSet();
+ SfxItemPoolCache aCache( pDocument->GetPool(), pSet );
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+ SCROW nEndRow = rRange.aEnd.Row();
+ for ( SCROW nRow = rRange.aStart.Row(); nRow <= nEndRow; nRow++ )
+ {
+ SCROW nRow1, nRow2;
+ const ScPatternAttr* pPattern = pAttrArray->GetPatternRange(
+ nRow1, nRow2, nRow );
+ ULONG nFormat = pPattern->GetNumberFormat( pFormatter );
+ short nOldType = pFormatter->GetType( nFormat );
+ if ( nOldType == nNewType || pFormatter->IsCompatible( nOldType, nNewType ) )
+ nRow = nRow2;
+ else
+ {
+ SCROW nNewRow1 = Max( nRow1, nRow );
+ SCROW nNewRow2 = Min( nRow2, nEndRow );
+ pAttrArray->ApplyCacheArea( nNewRow1, nNewRow2, &aCache );
+ nRow = nNewRow2;
+ }
+ }
+}
+
+
+void ScColumn::ApplyStyle( SCROW nRow, const ScStyleSheet& rStyle )
+{
+ const ScPatternAttr* pPattern = pAttrArray->GetPattern(nRow);
+ ScPatternAttr* pNewPattern = new ScPatternAttr(*pPattern);
+ if (pNewPattern)
+ {
+ pNewPattern->SetStyleSheet((ScStyleSheet*)&rStyle);
+ pAttrArray->SetPattern(nRow, pNewPattern, TRUE);
+ delete pNewPattern;
+ }
+}
+
+
+void ScColumn::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleSheet& rStyle )
+{
+ pAttrArray->ApplyStyleArea(nStartRow, nEndRow, (ScStyleSheet*)&rStyle);
+}
+
+
+void ScColumn::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
+{
+ SCROW nTop;
+ SCROW nBottom;
+
+ if ( rMark.IsMultiMarked() )
+ {
+ ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
+ while (aMarkIter.Next( nTop, nBottom ))
+ pAttrArray->ApplyStyleArea(nTop, nBottom, (ScStyleSheet*)&rStyle);
+ }
+}
+
+
+void ScColumn::ApplySelectionLineStyle( const ScMarkData& rMark,
+ const SvxBorderLine* pLine, BOOL bColorOnly )
+{
+ if ( bColorOnly && !pLine )
+ return;
+
+ SCROW nTop;
+ SCROW nBottom;
+
+ if (rMark.IsMultiMarked())
+ {
+ ScMarkArrayIter aMarkIter( rMark.GetArray()+nCol );
+ while (aMarkIter.Next( nTop, nBottom ))
+ pAttrArray->ApplyLineStyleArea(nTop, nBottom, pLine, bColorOnly );
+ }
+}
+
+
+const ScStyleSheet* ScColumn::GetStyle( SCROW nRow ) const
+{
+ return pAttrArray->GetPattern( nRow )->GetStyleSheet();
+}
+
+
+const ScStyleSheet* ScColumn::GetSelectionStyle( const ScMarkData& rMark, BOOL& rFound ) const
+{
+ rFound = FALSE;
+ if (!rMark.IsMultiMarked())
+ {
+ DBG_ERROR("ScColumn::GetSelectionStyle ohne Selektion");
+ return NULL;
+ }
+
+ BOOL bEqual = TRUE;
+
+ const ScStyleSheet* pStyle = NULL;
+ const ScStyleSheet* pNewStyle;
+
+ ScMarkArrayIter aMarkIter( rMark.GetArray() + nCol );
+ SCROW nTop;
+ SCROW nBottom;
+ while (bEqual && aMarkIter.Next( nTop, nBottom ))
+ {
+ ScAttrIterator aAttrIter( pAttrArray, nTop, nBottom );
+ SCROW nRow;
+ SCROW nDummy;
+ const ScPatternAttr* pPattern;
+ while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
+ {
+ pNewStyle = pPattern->GetStyleSheet();
+ rFound = TRUE;
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = FALSE; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+
+const ScStyleSheet* ScColumn::GetAreaStyle( BOOL& rFound, SCROW nRow1, SCROW nRow2 ) const
+{
+ rFound = FALSE;
+
+ BOOL bEqual = TRUE;
+
+ const ScStyleSheet* pStyle = NULL;
+ const ScStyleSheet* pNewStyle;
+
+ ScAttrIterator aAttrIter( pAttrArray, nRow1, nRow2 );
+ SCROW nRow;
+ SCROW nDummy;
+ const ScPatternAttr* pPattern;
+ while (bEqual && ( pPattern = aAttrIter.Next( nRow, nDummy ) ) != NULL)
+ {
+ pNewStyle = pPattern->GetStyleSheet();
+ rFound = TRUE;
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = FALSE; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+
+void ScColumn::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, BOOL* pUsed, BOOL bReset )
+{
+ pAttrArray->FindStyleSheet( pStyleSheet, pUsed, bReset );
+}
+
+
+BOOL ScColumn::IsStyleSheetUsed( const ScStyleSheet& rStyle, BOOL bGatherAllStyles ) const
+{
+ return pAttrArray->IsStyleSheetUsed( rStyle, bGatherAllStyles );
+}
+
+
+BOOL ScColumn::ApplyFlags( SCROW nStartRow, SCROW nEndRow, INT16 nFlags )
+{
+ return pAttrArray->ApplyFlags( nStartRow, nEndRow, nFlags );
+}
+
+
+BOOL ScColumn::RemoveFlags( SCROW nStartRow, SCROW nEndRow, INT16 nFlags )
+{
+ return pAttrArray->RemoveFlags( nStartRow, nEndRow, nFlags );
+}
+
+
+void ScColumn::ClearItems( SCROW nStartRow, SCROW nEndRow, const USHORT* pWhich )
+{
+ pAttrArray->ClearItems( nStartRow, nEndRow, pWhich );
+}
+
+
+void ScColumn::SetPattern( SCROW nRow, const ScPatternAttr& rPatAttr, BOOL bPutToPool )
+{
+ pAttrArray->SetPattern( nRow, &rPatAttr, bPutToPool );
+}
+
+
+void ScColumn::SetPatternArea( SCROW nStartRow, SCROW nEndRow,
+ const ScPatternAttr& rPatAttr, BOOL bPutToPool )
+{
+ pAttrArray->SetPatternArea( nStartRow, nEndRow, &rPatAttr, bPutToPool );
+}
+
+
+void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
+{
+ // um nur ein neues SetItem zu erzeugen, brauchen wir keinen SfxItemPoolCache.
+ //! Achtung: der SfxItemPoolCache scheint zuviele Refs fuer das neue SetItem zu erzeugen ??
+
+ ScDocumentPool* pDocPool = pDocument->GetPool();
+
+ const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
+ ScPatternAttr* pTemp = new ScPatternAttr(*pOldPattern);
+ pTemp->GetItemSet().Put(rAttr);
+ const ScPatternAttr* pNewPattern = (const ScPatternAttr*) &pDocPool->Put( *pTemp );
+
+ if ( pNewPattern != pOldPattern )
+ pAttrArray->SetPattern( nRow, pNewPattern );
+ else
+ pDocPool->Remove( *pNewPattern ); // ausser Spesen nichts gewesen
+
+ delete pTemp;
+
+ // alte Version mit SfxItemPoolCache:
+#if 0
+ SfxItemPoolCache aCache( pDocument->GetPool(), &rAttr );
+
+ const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
+
+ // TRUE = alten Eintrag behalten
+
+ ScPatternAttr* pNewPattern = (ScPatternAttr*) &aCache.ApplyTo( *pPattern, TRUE );
+ ScDocumentPool::CheckRef( *pPattern );
+ ScDocumentPool::CheckRef( *pNewPattern );
+
+ if (pNewPattern != pPattern)
+ pAttrArray->SetPattern( nRow, pNewPattern );
+#endif
+}
+
+#ifdef _MSC_VER
+#pragma optimize ( "", off )
+#endif
+
+
+BOOL ScColumn::Search( SCROW nRow, SCSIZE& nIndex ) const
+{
+ if ( !pItems || !nCount )
+ {
+ nIndex = 0;
+ return FALSE;
+ }
+ SCROW nMinRow = pItems[0].nRow;
+ if ( nRow <= nMinRow )
+ {
+ nIndex = 0;
+ return nRow == nMinRow;
+ }
+ SCROW nMaxRow = pItems[nCount-1].nRow;
+ if ( nRow >= nMaxRow )
+ {
+ if ( nRow == nMaxRow )
+ {
+ nIndex = nCount - 1;
+ return TRUE;
+ }
+ else
+ {
+ nIndex = nCount;
+ return FALSE;
+ }
+ }
+
+ long nOldLo, nOldHi;
+ long nLo = nOldLo = 0;
+ long nHi = nOldHi = Min(static_cast<long>(nCount)-1, static_cast<long>(nRow) );
+ long i = 0;
+ BOOL bFound = FALSE;
+ // quite continuous distribution? => interpolating search
+ BOOL bInterpol = (static_cast<SCSIZE>(nMaxRow - nMinRow) < nCount * 2);
+ SCROW nR;
+
+ while ( !bFound && nLo <= nHi )
+ {
+ if ( !bInterpol || nHi - nLo < 3 )
+ i = (nLo+nHi) / 2; // no effort, no division by zero
+ else
+ { // interpolating search
+ long nLoRow = pItems[nLo].nRow; // no unsigned underflow upon substraction
+ i = nLo + (long)((long)(nRow - nLoRow) * (nHi - nLo)
+ / (pItems[nHi].nRow - nLoRow));
+ if ( i < 0 || static_cast<SCSIZE>(i) >= nCount )
+ { // oops ...
+ i = (nLo+nHi) / 2;
+ bInterpol = FALSE;
+ }
+ }
+ nR = pItems[i].nRow;
+ if ( nR < nRow )
+ {
+ nLo = i+1;
+ if ( bInterpol )
+ {
+ if ( nLo <= nOldLo )
+ bInterpol = FALSE;
+ else
+ nOldLo = nLo;
+ }
+ }
+ else
+ {
+ if ( nR > nRow )
+ {
+ nHi = i-1;
+ if ( bInterpol )
+ {
+ if ( nHi >= nOldHi )
+ bInterpol = FALSE;
+ else
+ nOldHi = nHi;
+ }
+ }
+ else
+ bFound = TRUE;
+ }
+ }
+ if (bFound)
+ nIndex = static_cast<SCSIZE>(i);
+ else
+ nIndex = static_cast<SCSIZE>(nLo); // rear index
+ return bFound;
+}
+
+#ifdef _MSC_VER
+#pragma optimize ( "", on )
+#endif
+
+
+ScBaseCell* ScColumn::GetCell( SCROW nRow ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ return pItems[nIndex].pCell;
+ return NULL;
+}
+
+
+void ScColumn::Resize( SCSIZE nSize )
+{
+ if (nSize > sal::static_int_cast<SCSIZE>(MAXROWCOUNT))
+ nSize = MAXROWCOUNT;
+ if (nSize < nCount)
+ nSize = nCount;
+
+ ColEntry* pNewItems;
+ if (nSize)
+ {
+ SCSIZE nNewSize = nSize + COLUMN_DELTA - 1;
+ nNewSize -= nNewSize % COLUMN_DELTA;
+ nLimit = nNewSize;
+ pNewItems = new ColEntry[nLimit];
+ }
+ else
+ {
+ nLimit = 0;
+ pNewItems = NULL;
+ }
+ if (pItems)
+ {
+ if (pNewItems)
+ memmove( pNewItems, pItems, nCount * sizeof(ColEntry) );
+ delete[] pItems;
+ }
+ pItems = pNewItems;
+}
+
+// SwapRow zum Sortieren
+
+namespace {
+
+/** Moves broadcaster from old cell to new cell if exists, otherwise creates a new note cell. */
+void lclTakeBroadcaster( ScBaseCell*& rpCell, SvtBroadcaster* pBC )
+{
+ if( pBC )
+ {
+ if( rpCell )
+ rpCell->TakeBroadcaster( pBC );
+ else
+ rpCell = new ScNoteCell( pBC );
+ }
+}
+
+} // namespace
+
+void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
+{
+ /* Simple swap of cell pointers does not work if broadcasters exist (crash
+ if cell broadcasts directly or indirectly to itself). While swapping
+ the cells, broadcasters have to remain at old positions! */
+
+ /* While cloning cells, do not clone notes, but move note pointers to new
+ cells. This prevents creation of new caption drawing objects for every
+ swap operation while sorting. */
+
+ ScBaseCell* pCell1 = 0;
+ SCSIZE nIndex1;
+ if ( Search( nRow1, nIndex1 ) )
+ pCell1 = pItems[nIndex1].pCell;
+
+ ScBaseCell* pCell2 = 0;
+ SCSIZE nIndex2;
+ if ( Search( nRow2, nIndex2 ) )
+ pCell2 = pItems[nIndex2].pCell;
+
+ // no cells found, nothing to do
+ if ( !pCell1 && !pCell2 )
+ return ;
+
+ // swap variables if first cell is empty, to save some code below
+ if ( !pCell1 )
+ {
+ ::std::swap( nRow1, nRow2 );
+ ::std::swap( nIndex1, nIndex2 );
+ ::std::swap( pCell1, pCell2 );
+ }
+
+ // from here: first cell (pCell1, nIndex1) exists always
+
+ ScAddress aPos1( nCol, nRow1, nTab );
+ ScAddress aPos2( nCol, nRow2, nTab );
+
+ CellType eType1 = pCell1->GetCellType();
+ CellType eType2 = pCell2 ? pCell2->GetCellType() : CELLTYPE_NONE;
+
+ ScFormulaCell* pFmlaCell1 = (eType1 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
+ ScFormulaCell* pFmlaCell2 = (eType2 == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell2 ) : 0;
+
+ // simple swap if no formula cells present
+ if ( !pFmlaCell1 && !pFmlaCell2 )
+ {
+ // remember cell broadcasters, must remain at old position
+ SvtBroadcaster* pBC1 = pCell1->ReleaseBroadcaster();
+
+ if ( pCell2 )
+ {
+ /* Both cells exist, no formula cells involved, a simple swap can
+ be performed (but keep broadcasters and notes at old position). */
+ pItems[nIndex1].pCell = pCell2;
+ pItems[nIndex2].pCell = pCell1;
+
+ SvtBroadcaster* pBC2 = pCell2->ReleaseBroadcaster();
+ pCell1->TakeBroadcaster( pBC2 );
+ pCell2->TakeBroadcaster( pBC1 );
+
+ ScHint aHint1( SC_HINT_DATACHANGED, aPos1, pCell2 );
+ pDocument->Broadcast( aHint1 );
+ ScHint aHint2( SC_HINT_DATACHANGED, aPos2, pCell1 );
+ pDocument->Broadcast( aHint2 );
+ }
+ else
+ {
+ ScNoteCell* pDummyCell = pBC1 ? new ScNoteCell( pBC1 ) : 0;
+ if ( pDummyCell )
+ {
+ // insert dummy note cell (without note) containing old broadcaster
+ pItems[nIndex1].pCell = pDummyCell;
+ }
+ else
+ {
+ // remove ColEntry at old position
+ --nCount;
+ memmove( &pItems[nIndex1], &pItems[nIndex1 + 1], (nCount - nIndex1) * sizeof(ColEntry) );
+ pItems[nCount].nRow = 0;
+ pItems[nCount].pCell = 0;
+ }
+
+ // insert ColEntry at new position
+ Insert( nRow2, pCell1 );
+ pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED, aPos1, pDummyCell ) );
+ }
+
+ return;
+ }
+
+ // from here: at least one of the cells is a formula cell
+
+ /* Never move any array formulas. Disabling sort if parts of array
+ formulas are contained is done at UI. */
+ if ( (pFmlaCell1 && (pFmlaCell1->GetMatrixFlag() != 0)) || (pFmlaCell2 && (pFmlaCell2->GetMatrixFlag() != 0)) )
+ return;
+
+ // do not swap, if formulas are equal
+ if ( pFmlaCell1 && pFmlaCell2 )
+ {
+ ScTokenArray* pCode1 = pFmlaCell1->GetCode();
+ ScTokenArray* pCode2 = pFmlaCell2->GetCode();
+
+ if (pCode1->GetLen() == pCode2->GetLen()) // nicht-UPN
+ {
+ BOOL bEqual = TRUE;
+ USHORT nLen = pCode1->GetLen();
+ FormulaToken** ppToken1 = pCode1->GetArray();
+ FormulaToken** ppToken2 = pCode2->GetArray();
+ for (USHORT i=0; i<nLen; i++)
+ {
+ if ( !ppToken1[i]->TextEqual(*(ppToken2[i])) ||
+ ppToken1[i]->Is3DRef() || ppToken2[i]->Is3DRef() )
+ {
+ bEqual = FALSE;
+ break;
+ }
+ }
+
+ // do not swap formula cells with equal formulas, but swap notes
+ if (bEqual)
+ {
+ ScPostIt* pNote1 = pCell1->ReleaseNote();
+ pCell1->TakeNote( pCell2->ReleaseNote() );
+ pCell2->TakeNote( pNote1 );
+ return;
+ }
+ }
+ }
+
+ // hier kein UpdateReference wegen #30529# - mitsortiert werden nur noch relative Referenzen
+// long dy = (long)nRow2 - (long)nRow1;
+
+ /* Create clone of pCell1 at position of pCell2 (pCell1 exists always, see
+ variable swapping above). Do not clone the note, but move pointer of
+ old note to new cell. */
+ ScBaseCell* pNew2 = pCell1->CloneWithoutNote( *pDocument, aPos2, SC_CLONECELL_ADJUST3DREL );
+ pNew2->TakeNote( pCell1->ReleaseNote() );
+
+ /* Create clone of pCell2 at position of pCell1. Do not clone the note,
+ but move pointer of old note to new cell. */
+ ScBaseCell* pNew1 = 0;
+ if ( pCell2 )
+ {
+ pNew1 = pCell2->CloneWithoutNote( *pDocument, aPos1, SC_CLONECELL_ADJUST3DREL );
+ pNew1->TakeNote( pCell2->ReleaseNote() );
+ }
+
+ // move old broadcasters new cells at the same old position
+ SvtBroadcaster* pBC1 = pCell1->ReleaseBroadcaster();
+ lclTakeBroadcaster( pNew1, pBC1 );
+ SvtBroadcaster* pBC2 = pCell2 ? pCell2->ReleaseBroadcaster() : 0;
+ lclTakeBroadcaster( pNew2, pBC2 );
+
+ /* Insert the new cells. Old cell has to be deleted, if there is no new
+ cell (call to Insert deletes old cell by itself). */
+ if ( !pNew1 )
+ Delete( nRow1 ); // deletes pCell1
+ else
+ Insert( nRow1, pNew1 ); // deletes pCell1, inserts pNew1
+
+ if ( pCell2 && !pNew2 )
+ Delete( nRow2 ); // deletes pCell2
+ else if ( pNew2 )
+ Insert( nRow2, pNew2 ); // deletes pCell2 (if existing), inserts pNew2
+
+ // #64122# Bei Formeln hinterher nochmal broadcasten, damit die Formel nicht in irgendwelchen
+ // FormulaTrack-Listen landet, ohne die Broadcaster beruecksichtigt zu haben
+ // (erst hier, wenn beide Zellen eingefuegt sind)
+ if ( pBC1 && pFmlaCell2 )
+ pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED, aPos1, pNew1 ) );
+ if ( pBC2 && pFmlaCell1 )
+ pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED, aPos2, pNew2 ) );
+}
+
+
+void ScColumn::SwapCell( SCROW nRow, ScColumn& rCol)
+{
+ ScBaseCell* pCell1 = 0;
+ SCSIZE nIndex1;
+ if ( Search( nRow, nIndex1 ) )
+ pCell1 = pItems[nIndex1].pCell;
+
+ ScBaseCell* pCell2 = 0;
+ SCSIZE nIndex2;
+ if ( rCol.Search( nRow, nIndex2 ) )
+ pCell2 = rCol.pItems[nIndex2].pCell;
+
+ // reverse call if own cell is missing (ensures own existing cell in following code)
+ if( !pCell1 )
+ {
+ if( pCell2 )
+ rCol.SwapCell( nRow, *this );
+ return;
+ }
+
+ // from here: own cell (pCell1, nIndex1) exists always
+
+ ScFormulaCell* pFmlaCell1 = (pCell1->GetCellType() == CELLTYPE_FORMULA) ? static_cast< ScFormulaCell* >( pCell1 ) : 0;
+ ScFormulaCell* pFmlaCell2 = (pCell2 && (pCell2->GetCellType() == CELLTYPE_FORMULA)) ? static_cast< ScFormulaCell* >( pCell2 ) : 0;
+
+ if ( pCell2 )
+ {
+ // Tauschen
+ pItems[nIndex1].pCell = pCell2;
+ rCol.pItems[nIndex2].pCell = pCell1;
+ // Referenzen aktualisieren
+ SCsCOL dx = rCol.nCol - nCol;
+ if ( pFmlaCell1 )
+ {
+ ScRange aRange( ScAddress( rCol.nCol, 0, nTab ),
+ ScAddress( rCol.nCol, MAXROW, nTab ) );
+ pFmlaCell1->aPos.SetCol( rCol.nCol );
+ pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0);
+ }
+ if ( pFmlaCell2 )
+ {
+ ScRange aRange( ScAddress( nCol, 0, nTab ),
+ ScAddress( nCol, MAXROW, nTab ) );
+ pFmlaCell2->aPos.SetCol( nCol );
+ pFmlaCell2->UpdateReference(URM_MOVE, aRange, -dx, 0, 0);
+ }
+ }
+ else
+ {
+ // Loeschen
+ --nCount;
+ memmove( &pItems[nIndex1], &pItems[nIndex1 + 1], (nCount - nIndex1) * sizeof(ColEntry) );
+ pItems[nCount].nRow = 0;
+ pItems[nCount].pCell = 0;
+ // Referenzen aktualisieren
+ SCsCOL dx = rCol.nCol - nCol;
+ if ( pFmlaCell1 )
+ {
+ ScRange aRange( ScAddress( rCol.nCol, 0, nTab ),
+ ScAddress( rCol.nCol, MAXROW, nTab ) );
+ pFmlaCell1->aPos.SetCol( rCol.nCol );
+ pFmlaCell1->UpdateReference(URM_MOVE, aRange, dx, 0, 0);
+ }
+ // Einfuegen
+ rCol.Insert(nRow, pCell1);
+ }
+}
+
+
+BOOL ScColumn::TestInsertCol( SCROW nStartRow, SCROW nEndRow) const
+{
+ if (!IsEmpty())
+ {
+ BOOL bTest = TRUE;
+ if (pItems)
+ for (SCSIZE i=0; (i<nCount) && bTest; i++)
+ bTest = (pItems[i].nRow < nStartRow) || (pItems[i].nRow > nEndRow)
+ || pItems[i].pCell->IsBlank();
+
+ // AttrArray testet nur zusammengefasste
+
+ if ((bTest) && (pAttrArray))
+ bTest = pAttrArray->TestInsertCol(nStartRow, nEndRow);
+
+ //! rausgeschobene Attribute bei Undo beruecksichtigen
+
+ return bTest;
+ }
+ else
+ return TRUE;
+}
+
+
+BOOL ScColumn::TestInsertRow( SCSIZE nSize ) const
+{
+ // AttrArray only looks for merged cells
+
+ if ( pItems && nCount )
+ return ( nSize <= sal::static_int_cast<SCSIZE>(MAXROW) &&
+ pItems[nCount-1].nRow <= MAXROW-(SCROW)nSize && pAttrArray->TestInsertRow( nSize ) );
+ else
+ return pAttrArray->TestInsertRow( nSize );
+
+#if 0
+ //! rausgeschobene Attribute bei Undo beruecksichtigen
+
+ if ( nSize > static_cast<SCSIZE>(MAXROW) )
+ return FALSE;
+
+ SCSIZE nVis = nCount;
+ while ( nVis && pItems[nVis-1].pCell->IsBlank() )
+ --nVis;
+
+ if ( nVis )
+ return ( pItems[nVis-1].nRow <= MAXROW-nSize );
+ else
+ return TRUE;
+#endif
+}
+
+
+void ScColumn::InsertRow( SCROW nStartRow, SCSIZE nSize )
+{
+ pAttrArray->InsertRow( nStartRow, nSize );
+
+ //! Search
+
+ if ( !pItems || !nCount )
+ return;
+
+ SCSIZE i;
+ Search( nStartRow, i );
+ if ( i >= nCount )
+ return ;
+
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+
+ SCSIZE nNewCount = nCount;
+ BOOL bCountChanged = FALSE;
+ ScAddress aAdr( nCol, 0, nTab );
+ ScHint aHint( SC_HINT_DATACHANGED, aAdr, NULL ); // only areas (ScBaseCell* == NULL)
+ ScAddress& rAddress = aHint.GetAddress();
+ // for sparse occupation use single broadcasts, not ranges
+ BOOL bSingleBroadcasts = (((pItems[nCount-1].nRow - pItems[i].nRow) /
+ (nCount - i)) > 1);
+ if ( bSingleBroadcasts )
+ {
+ SCROW nLastBroadcast = MAXROW+1;
+ for ( ; i < nCount; i++)
+ {
+ SCROW nOldRow = pItems[i].nRow;
+ // #43940# Aenderung Quelle broadcasten
+ if ( nLastBroadcast != nOldRow )
+ { // direkt aufeinanderfolgende nicht doppelt broadcasten
+ rAddress.SetRow( nOldRow );
+ pDocument->AreaBroadcast( aHint );
+ }
+ SCROW nNewRow = (pItems[i].nRow += nSize);
+ // #43940# Aenderung Ziel broadcasten
+ rAddress.SetRow( nNewRow );
+ pDocument->AreaBroadcast( aHint );
+ nLastBroadcast = nNewRow;
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
+ if ( nNewRow > MAXROW && !bCountChanged )
+ {
+ nNewCount = i;
+ bCountChanged = TRUE;
+ }
+ }
+ }
+ else
+ {
+ rAddress.SetRow( pItems[i].nRow );
+ ScRange aRange( rAddress );
+ for ( ; i < nCount; i++)
+ {
+ SCROW nNewRow = (pItems[i].nRow += nSize);
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
+ if ( nNewRow > MAXROW && !bCountChanged )
+ {
+ nNewCount = i;
+ bCountChanged = TRUE;
+ aRange.aEnd.SetRow( MAXROW );
+ }
+ }
+ if ( !bCountChanged )
+ aRange.aEnd.SetRow( pItems[nCount-1].nRow );
+ pDocument->AreaBroadcastInRange( aRange, aHint );
+ }
+
+ if (bCountChanged)
+ {
+ SCSIZE nDelCount = nCount - nNewCount;
+ ScBaseCell** ppDelCells = new ScBaseCell*[nDelCount];
+ SCROW* pDelRows = new SCROW[nDelCount];
+ for (i = 0; i < nDelCount; i++)
+ {
+ ppDelCells[i] = pItems[nNewCount+i].pCell;
+ pDelRows[i] = pItems[nNewCount+i].nRow;
+ }
+ nCount = nNewCount;
+
+ for (i = 0; i < nDelCount; i++)
+ {
+ ScBaseCell* pCell = ppDelCells[i];
+ DBG_ASSERT( pCell->IsBlank(), "sichtbare Zelle weggeschoben" );
+ SvtBroadcaster* pBC = pCell->GetBroadcaster();
+ if (pBC)
+ {
+ MoveListeners( *pBC, pDelRows[i] - nSize );
+ pCell->DeleteBroadcaster();
+ pCell->Delete();
+ }
+ }
+
+ delete pDelRows;
+ delete ppDelCells;
+ }
+
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScColumn::CopyToClip(SCROW nRow1, SCROW nRow2, ScColumn& rColumn, BOOL bKeepScenarioFlags, BOOL bCloneNoteCaptions)
+{
+ pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray,
+ bKeepScenarioFlags ? (SC_MF_ALL & ~SC_MF_SCENARIO) : SC_MF_ALL );
+
+ SCSIZE i;
+ SCSIZE nBlockCount = 0;
+ SCSIZE nStartIndex = 0, nEndIndex = 0;
+ for (i = 0; i < nCount; i++)
+ if ((pItems[i].nRow >= nRow1) && (pItems[i].nRow <= nRow2))
+ {
+ if (!nBlockCount)
+ nStartIndex = i;
+ nEndIndex = i;
+ ++nBlockCount;
+
+ // im Clipboard muessen interpretierte Zellen stehen, um andere Formate
+ // (Text, Grafik...) erzueugen zu koennen
+
+ if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*) pItems[i].pCell;
+ if (pFCell->GetDirty() && pDocument->GetAutoCalc())
+ pFCell->Interpret();
+ }
+ }
+
+ if (nBlockCount)
+ {
+ int nCloneFlags = bCloneNoteCaptions ? SC_CLONECELL_DEFAULT : SC_CLONECELL_NOCAPTION;
+ rColumn.Resize( rColumn.GetCellCount() + nBlockCount );
+ ScAddress aPos( rColumn.nCol, 0, rColumn.nTab );
+ for (i = nStartIndex; i <= nEndIndex; i++)
+ {
+ aPos.SetRow( pItems[i].nRow );
+ rColumn.Append( aPos.Row(), pItems[i].pCell->CloneWithNote( *rColumn.pDocument, aPos, nCloneFlags ) );
+ }
+ }
+}
+
+
+void ScColumn::CopyToColumn(SCROW nRow1, SCROW nRow2, USHORT nFlags, BOOL bMarked,
+ ScColumn& rColumn, const ScMarkData* pMarkData, BOOL bAsLink )
+{
+ if (bMarked)
+ {
+ SCROW nStart, nEnd;
+ if (pMarkData && pMarkData->IsMultiMarked())
+ {
+ ScMarkArrayIter aIter( pMarkData->GetArray()+nCol );
+
+ while ( aIter.Next( nStart, nEnd ) && nStart <= nRow2 )
+ {
+ if ( nEnd >= nRow1 )
+ CopyToColumn( Max(nRow1,nStart), Min(nRow2,nEnd),
+ nFlags, FALSE, rColumn, pMarkData, bAsLink );
+ }
+ }
+ else
+ {
+ DBG_ERROR("CopyToColumn: bMarked, aber keine Markierung");
+ }
+ return;
+ }
+
+ if ( (nFlags & IDF_ATTRIB) != 0 )
+ {
+ if ( (nFlags & IDF_STYLES) != IDF_STYLES )
+ { // StyleSheets im Zieldokument bleiben erhalten
+ // z.B. DIF und RTF Clipboard-Import
+ for ( SCROW nRow = nRow1; nRow <= nRow2; nRow++ )
+ {
+ const ScStyleSheet* pStyle =
+ rColumn.pAttrArray->GetPattern( nRow )->GetStyleSheet();
+ const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
+ ScPatternAttr* pNewPattern = new ScPatternAttr( *pPattern );
+ pNewPattern->SetStyleSheet( (ScStyleSheet*)pStyle );
+ rColumn.pAttrArray->SetPattern( nRow, pNewPattern, TRUE );
+ delete pNewPattern;
+ }
+ }
+ else
+ pAttrArray->CopyArea( nRow1, nRow2, 0, *rColumn.pAttrArray);
+ }
+
+
+ if ((nFlags & IDF_CONTENTS) != 0)
+ {
+ SCSIZE i;
+ SCSIZE nBlockCount = 0;
+ SCSIZE nStartIndex = 0, nEndIndex = 0;
+ for (i = 0; i < nCount; i++)
+ if ((pItems[i].nRow >= nRow1) && (pItems[i].nRow <= nRow2))
+ {
+ if (!nBlockCount)
+ nStartIndex = i;
+ nEndIndex = i;
+ ++nBlockCount;
+ }
+
+ if (nBlockCount)
+ {
+ rColumn.Resize( rColumn.GetCellCount() + nBlockCount );
+ ScAddress aDestPos( rColumn.nCol, 0, rColumn.nTab );
+ for (i = nStartIndex; i <= nEndIndex; i++)
+ {
+ aDestPos.SetRow( pItems[i].nRow );
+ ScBaseCell* pNew = bAsLink ?
+ CreateRefCell( rColumn.pDocument, aDestPos, i, nFlags ) :
+ CloneCell( i, nFlags, *rColumn.pDocument, aDestPos );
+
+ if (pNew)
+ rColumn.Insert(pItems[i].nRow, pNew);
+ }
+ }
+ }
+}
+
+
+void ScColumn::UndoToColumn(SCROW nRow1, SCROW nRow2, USHORT nFlags, BOOL bMarked,
+ ScColumn& rColumn, const ScMarkData* pMarkData )
+{
+ if (nRow1 > 0)
+ CopyToColumn( 0, nRow1-1, IDF_FORMULA, FALSE, rColumn );
+
+ CopyToColumn( nRow1, nRow2, nFlags, bMarked, rColumn, pMarkData ); //! bMarked ????
+
+ if (nRow2 < MAXROW)
+ CopyToColumn( nRow2+1, MAXROW, IDF_FORMULA, FALSE, rColumn );
+}
+
+
+void ScColumn::CopyUpdated( const ScColumn& rPosCol, ScColumn& rDestCol ) const
+{
+ ScDocument& rDestDoc = *rDestCol.pDocument;
+ ScAddress aDestPos( rDestCol.nCol, 0, rDestCol.nTab );
+
+ SCSIZE nPosCount = rPosCol.nCount;
+ for (SCSIZE nPosIndex = 0; nPosIndex < nPosCount; nPosIndex++)
+ {
+ aDestPos.SetRow( rPosCol.pItems[nPosIndex].nRow );
+ SCSIZE nThisIndex;
+ if ( Search( aDestPos.Row(), nThisIndex ) )
+ {
+ ScBaseCell* pNew = pItems[nThisIndex].pCell->CloneWithNote( rDestDoc, aDestPos );
+ rDestCol.Insert( aDestPos.Row(), pNew );
+ }
+ }
+
+ // Dummy:
+ // CopyToColumn( 0,MAXROW, IDF_FORMULA, FALSE, rDestCol, NULL, FALSE );
+}
+
+
+void ScColumn::CopyScenarioFrom( const ScColumn& rSrcCol )
+{
+ // Dies ist die Szenario-Tabelle, die Daten werden hineinkopiert
+
+ ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
+ SCROW nStart, nEnd;
+ const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
+ while (pPattern)
+ {
+ if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
+ {
+ DeleteArea( nStart, nEnd, IDF_CONTENTS );
+ ((ScColumn&)rSrcCol).
+ CopyToColumn( nStart, nEnd, IDF_CONTENTS, FALSE, *this );
+
+ // UpdateUsed nicht noetig, schon in TestCopyScenario passiert
+
+ SCsTAB nDz = nTab - rSrcCol.nTab;
+ UpdateReference(URM_COPY, nCol, nStart, nTab,
+ nCol, nEnd, nTab,
+ 0, 0, nDz, NULL);
+ UpdateCompile();
+ }
+
+ //! CopyToColumn "const" machen !!!
+
+ pPattern = aAttrIter.Next( nStart, nEnd );
+ }
+}
+
+
+void ScColumn::CopyScenarioTo( ScColumn& rDestCol ) const
+{
+ // Dies ist die Szenario-Tabelle, die Daten werden in die andere kopiert
+
+ ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
+ SCROW nStart, nEnd;
+ const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
+ while (pPattern)
+ {
+ if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
+ {
+ rDestCol.DeleteArea( nStart, nEnd, IDF_CONTENTS );
+ ((ScColumn*)this)->
+ CopyToColumn( nStart, nEnd, IDF_CONTENTS, FALSE, rDestCol );
+
+ // UpdateUsed nicht noetig, schon in TestCopyScenario passiert
+
+ SCsTAB nDz = rDestCol.nTab - nTab;
+ rDestCol.UpdateReference(URM_COPY, rDestCol.nCol, nStart, rDestCol.nTab,
+ rDestCol.nCol, nEnd, rDestCol.nTab,
+ 0, 0, nDz, NULL);
+ rDestCol.UpdateCompile();
+ }
+
+ //! CopyToColumn "const" machen !!!
+
+ pPattern = aAttrIter.Next( nStart, nEnd );
+ }
+}
+
+
+BOOL ScColumn::TestCopyScenarioTo( const ScColumn& rDestCol ) const
+{
+ BOOL bOk = TRUE;
+ ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
+ SCROW nStart = 0, nEnd = 0;
+ const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
+ while (pPattern && bOk)
+ {
+ if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
+ if ( rDestCol.pAttrArray->HasAttrib( nStart, nEnd, HASATTR_PROTECTED ) )
+ bOk = FALSE;
+
+ pPattern = aAttrIter.Next( nStart, nEnd );
+ }
+ return bOk;
+}
+
+
+void ScColumn::MarkScenarioIn( ScMarkData& rDestMark ) const
+{
+ ScRange aRange( nCol, 0, nTab );
+
+ ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
+ SCROW nStart, nEnd;
+ const ScPatternAttr* pPattern = aAttrIter.Next( nStart, nEnd );
+ while (pPattern)
+ {
+ if ( ((ScMergeFlagAttr&)pPattern->GetItem( ATTR_MERGE_FLAG )).IsScenario() )
+ {
+ aRange.aStart.SetRow( nStart );
+ aRange.aEnd.SetRow( nEnd );
+ rDestMark.SetMultiMarkArea( aRange, TRUE );
+ }
+
+ pPattern = aAttrIter.Next( nStart, nEnd );
+ }
+}
+
+
+void ScColumn::SwapCol(ScColumn& rCol)
+{
+ SCSIZE nTemp;
+
+ nTemp = rCol.nCount;
+ rCol.nCount = nCount;
+ nCount = nTemp;
+
+ nTemp = rCol.nLimit;
+ rCol.nLimit = nLimit;
+ nLimit = nTemp;
+
+ ColEntry* pTempItems = rCol.pItems;
+ rCol.pItems = pItems;
+ pItems = pTempItems;
+
+ ScAttrArray* pTempAttr = rCol.pAttrArray;
+ rCol.pAttrArray = pAttrArray;
+ pAttrArray = pTempAttr;
+
+ // #38415# AttrArray muss richtige Spaltennummer haben
+ pAttrArray->SetCol(nCol);
+ rCol.pAttrArray->SetCol(rCol.nCol);
+
+ SCSIZE i;
+ if (pItems)
+ for (i = 0; i < nCount; i++)
+ {
+ ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
+ if( pCell->GetCellType() == CELLTYPE_FORMULA)
+ pCell->aPos.SetCol(nCol);
+ }
+ if (rCol.pItems)
+ for (i = 0; i < rCol.nCount; i++)
+ {
+ ScFormulaCell* pCell = (ScFormulaCell*) rCol.pItems[i].pCell;
+ if( pCell->GetCellType() == CELLTYPE_FORMULA)
+ pCell->aPos.SetCol(rCol.nCol);
+ }
+}
+
+
+void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
+{
+ pAttrArray->MoveTo(nStartRow, nEndRow, *rCol.pAttrArray);
+
+ if (pItems)
+ {
+ ::std::vector<SCROW> aRows;
+ bool bConsecutive = true;
+ SCSIZE i;
+ Search( nStartRow, i); // i points to start row or position thereafter
+ SCSIZE nStartPos = i;
+ for ( ; i < nCount && pItems[i].nRow <= nEndRow; ++i)
+ {
+ SCROW nRow = pItems[i].nRow;
+ aRows.push_back( nRow);
+ rCol.Insert( nRow, pItems[i].pCell);
+ if (nRow != pItems[i].nRow)
+ { // Listener inserted
+ bConsecutive = false;
+ Search( nRow, i);
+ }
+ }
+ SCSIZE nStopPos = i;
+ if (nStartPos < nStopPos)
+ {
+ // Create list of ranges of cell entry positions
+ typedef ::std::pair<SCSIZE,SCSIZE> PosPair;
+ typedef ::std::vector<PosPair> EntryPosPairs;
+ EntryPosPairs aEntries;
+ if (bConsecutive)
+ aEntries.push_back( PosPair(nStartPos, nStopPos));
+ else
+ {
+ bool bFirst = true;
+ nStopPos = 0;
+ for (::std::vector<SCROW>::const_iterator it( aRows.begin());
+ it != aRows.end() && nStopPos < nCount; ++it,
+ ++nStopPos)
+ {
+ if (!bFirst && *it != pItems[nStopPos].nRow)
+ {
+ aEntries.push_back( PosPair(nStartPos, nStopPos));
+ bFirst = true;
+ }
+ if (bFirst && Search( *it, nStartPos))
+ {
+ bFirst = false;
+ nStopPos = nStartPos;
+ }
+ }
+ if (!bFirst && nStartPos < nStopPos)
+ aEntries.push_back( PosPair(nStartPos, nStopPos));
+ }
+ // Broadcast changes
+ ScAddress aAdr( nCol, 0, nTab );
+ ScHint aHint( SC_HINT_DYING, aAdr, NULL ); // areas only
+ ScAddress& rAddress = aHint.GetAddress();
+ ScNoteCell* pNoteCell = new ScNoteCell; // Dummy like in DeleteRange
+
+ // #121990# must iterate backwards, because indexes of following cells become invalid
+ for (EntryPosPairs::reverse_iterator it( aEntries.rbegin());
+ it != aEntries.rend(); ++it)
+ {
+ nStartPos = (*it).first;
+ nStopPos = (*it).second;
+ for (i=nStartPos; i<nStopPos; ++i)
+ pItems[i].pCell = pNoteCell;
+ for (i=nStartPos; i<nStopPos; ++i)
+ {
+ rAddress.SetRow( pItems[i].nRow );
+ pDocument->AreaBroadcast( aHint );
+ }
+ nCount -= nStopPos - nStartPos;
+ memmove( &pItems[nStartPos], &pItems[nStopPos],
+ (nCount - nStartPos) * sizeof(ColEntry) );
+ }
+ delete pNoteCell;
+ pItems[nCount].nRow = 0;
+ pItems[nCount].pCell = NULL;
+ }
+ }
+}
+
+
+void ScColumn::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ ScDocument* pUndoDoc )
+{
+ if (pItems)
+ {
+ ScRange aRange( ScAddress( nCol1, nRow1, nTab1 ),
+ ScAddress( nCol2, nRow2, nTab2 ) );
+ if ( eUpdateRefMode == URM_COPY && nRow1 == nRow2 )
+ { // z.B. eine einzelne Zelle aus dem Clipboard eingefuegt
+ SCSIZE nIndex;
+ if ( Search( nRow1, nIndex ) )
+ {
+ ScFormulaCell* pCell = (ScFormulaCell*) pItems[nIndex].pCell;
+ if( pCell->GetCellType() == CELLTYPE_FORMULA)
+ pCell->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
+ }
+ }
+ else
+ {
+ // #90279# For performance reasons two loop bodies instead of
+ // testing for update mode in each iteration.
+ // Anyways, this is still a bottleneck on large arrays with few
+ // formulas cells.
+ if ( eUpdateRefMode == URM_COPY )
+ {
+ SCSIZE i;
+ Search( nRow1, i );
+ for ( ; i < nCount; i++ )
+ {
+ SCROW nRow = pItems[i].nRow;
+ if ( nRow > nRow2 )
+ break;
+ ScBaseCell* pCell = pItems[i].pCell;
+ if( pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener removed/inserted?
+ }
+ }
+ }
+ else
+ {
+ SCSIZE i = 0;
+ for ( ; i < nCount; i++ )
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if( pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ SCROW nRow = pItems[i].nRow;
+ ((ScFormulaCell*)pCell)->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz, pUndoDoc );
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener removed/inserted?
+ }
+ }
+ }
+ }
+ }
+}
+
+
+void ScColumn::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
+ ScDocument* pUndoDoc )
+{
+ if (pItems)
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ SCROW nRow = pItems[i].nRow;
+ ((ScFormulaCell*)pCell)->UpdateTranspose( rSource, rDest, pUndoDoc );
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener geloescht/eingefuegt?
+ }
+ }
+}
+
+
+void ScColumn::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
+{
+ if (pItems)
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ SCROW nRow = pItems[i].nRow;
+ ((ScFormulaCell*)pCell)->UpdateGrow( rArea, nGrowX, nGrowY );
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener geloescht/eingefuegt?
+ }
+ }
+}
+
+
+void ScColumn::UpdateInsertTab( SCTAB nTable)
+{
+ if (nTab >= nTable)
+ pAttrArray->SetTab(++nTab);
+ if( pItems )
+ UpdateInsertTabOnlyCells( nTable );
+}
+
+
+void ScColumn::UpdateInsertTabOnlyCells( SCTAB nTable)
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
+ if( pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ SCROW nRow = pItems[i].nRow;
+ pCell->UpdateInsertTab(nTable);
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener geloescht/eingefuegt?
+ }
+ }
+}
+
+
+void ScColumn::UpdateInsertTabAbs(SCTAB nTable)
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
+ if( pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ SCROW nRow = pItems[i].nRow;
+ pCell->UpdateInsertTabAbs(nTable);
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener geloescht/eingefuegt?
+ }
+ }
+}
+
+
+void ScColumn::UpdateDeleteTab( SCTAB nTable, BOOL bIsMove, ScColumn* pRefUndo )
+{
+ if (nTab > nTable)
+ pAttrArray->SetTab(--nTab);
+
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ SCROW nRow = pItems[i].nRow;
+ ScFormulaCell* pOld = (ScFormulaCell*)pItems[i].pCell;
+
+ /* Do not copy cell note to the undo document. Undo will copy
+ back the formula cell while keeping the original note. */
+ ScBaseCell* pSave = pRefUndo ? pOld->CloneWithoutNote( *pDocument ) : 0;
+
+ BOOL bChanged = pOld->UpdateDeleteTab(nTable, bIsMove);
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener geloescht/eingefuegt?
+
+ if (pRefUndo)
+ {
+ if (bChanged)
+ pRefUndo->Insert( nRow, pSave );
+ else if(pSave)
+ pSave->Delete();
+ }
+ }
+}
+
+
+void ScColumn::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo )
+{
+ nTab = nTabNo;
+ pAttrArray->SetTab( nTabNo );
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScFormulaCell* pCell = (ScFormulaCell*) pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ SCROW nRow = pItems[i].nRow;
+ pCell->UpdateMoveTab( nOldPos, nNewPos, nTabNo );
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener geloescht/eingefuegt?
+ }
+ }
+}
+
+
+void ScColumn::UpdateCompile( BOOL bForceIfNameInUse )
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
+ if( p->GetCellType() == CELLTYPE_FORMULA )
+ {
+ SCROW nRow = pItems[i].nRow;
+ p->UpdateCompile( bForceIfNameInUse );
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener geloescht/eingefuegt?
+ }
+ }
+}
+
+
+void ScColumn::SetTabNo(SCTAB nNewTab)
+{
+ nTab = nNewTab;
+ pAttrArray->SetTab( nNewTab );
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
+ if( p->GetCellType() == CELLTYPE_FORMULA )
+ p->aPos.SetTab( nNewTab );
+ }
+}
+
+
+BOOL ScColumn::IsRangeNameInUse(SCROW nRow1, SCROW nRow2, USHORT nIndex) const
+{
+ BOOL bInUse = FALSE;
+ if (pItems)
+ for (SCSIZE i = 0; !bInUse && (i < nCount); i++)
+ if ((pItems[i].nRow >= nRow1) &&
+ (pItems[i].nRow <= nRow2) &&
+ (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
+ bInUse = ((ScFormulaCell*)pItems[i].pCell)->IsRangeNameInUse(nIndex);
+ return bInUse;
+}
+
+void ScColumn::FindRangeNamesInUse(SCROW nRow1, SCROW nRow2, std::set<USHORT>& rIndexes) const
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ if ((pItems[i].nRow >= nRow1) &&
+ (pItems[i].nRow <= nRow2) &&
+ (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
+ ((ScFormulaCell*)pItems[i].pCell)->FindRangeNamesInUse(rIndexes);
+}
+
+void ScColumn::ReplaceRangeNamesInUse(SCROW nRow1, SCROW nRow2,
+ const ScIndexMap& rMap )
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ if ((pItems[i].nRow >= nRow1) &&
+ (pItems[i].nRow <= nRow2) &&
+ (pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA))
+ {
+ SCROW nRow = pItems[i].nRow;
+ ((ScFormulaCell*)pItems[i].pCell)->ReplaceRangeNamesInUse( rMap );
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener geloescht/eingefuegt?
+ }
+ }
+}
+
+
+void ScColumn::SetDirtyVar()
+{
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
+ if( p->GetCellType() == CELLTYPE_FORMULA )
+ p->SetDirtyVar();
+ }
+}
+
+
+void ScColumn::SetDirty()
+{
+ // wird nur dokumentweit verwendet, kein FormulaTrack
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
+ if( p->GetCellType() == CELLTYPE_FORMULA )
+ {
+ p->SetDirtyVar();
+ if ( !pDocument->IsInFormulaTree( p ) )
+ pDocument->PutInFormulaTree( p );
+ }
+ }
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScColumn::SetDirty( const ScRange& rRange )
+{ // broadcastet alles innerhalb eines Range, mit FormulaTrack
+ if ( !pItems || !nCount )
+ return ;
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ SCROW nRow2 = rRange.aEnd.Row();
+ ScAddress aPos( nCol, 0, nTab );
+ ScHint aHint( SC_HINT_DATACHANGED, aPos, NULL );
+ SCROW nRow;
+ SCSIZE nIndex;
+ Search( rRange.aStart.Row(), nIndex );
+ while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->SetDirty();
+ else
+ {
+ aHint.GetAddress().SetRow( nRow );
+ aHint.SetCell( pCell );
+ pDocument->Broadcast( aHint );
+ }
+ nIndex++;
+ }
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScColumn::SetTableOpDirty( const ScRange& rRange )
+{
+ if ( !pItems || !nCount )
+ return ;
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // no multiple recalculation
+ SCROW nRow2 = rRange.aEnd.Row();
+ ScAddress aPos( nCol, 0, nTab );
+ ScHint aHint( SC_HINT_TABLEOPDIRTY, aPos, NULL );
+ SCROW nRow;
+ SCSIZE nIndex;
+ Search( rRange.aStart.Row(), nIndex );
+ while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->SetTableOpDirty();
+ else
+ {
+ aHint.GetAddress().SetRow( nRow );
+ aHint.SetCell( pCell );
+ pDocument->Broadcast( aHint );
+ }
+ nIndex++;
+ }
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScColumn::SetDirtyAfterLoad()
+{
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
+#if 1
+ // Simply set dirty and append to FormulaTree, without broadcasting,
+ // which is a magnitude faster. This is used to calculate the entire
+ // document, e.g. when loading alien file formats.
+ if ( p->GetCellType() == CELLTYPE_FORMULA )
+ p->SetDirtyAfterLoad();
+#else
+/* This was used with the binary file format that stored results, where only
+ * newly compiled and volatile functions and their dependents had to be
+ * recalculated, which was faster then. Since that was moved to 'binfilter' to
+ * convert to an XML file this isn't needed anymore, and not used for other
+ * file formats. Kept for reference in case mechanism needs to be reactivated
+ * for some file formats, we'd have to introduce a controlling parameter to
+ * this method here then.
+*/
+
+ // If the cell was alsready dirty because of CalcAfterLoad,
+ // FormulaTracking has to take place.
+ if ( p->GetCellType() == CELLTYPE_FORMULA && p->GetDirty() )
+ p->SetDirty();
+#endif
+ }
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScColumn::SetRelNameDirty()
+{
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScFormulaCell* p = (ScFormulaCell*) pItems[i].pCell;
+ if( p->GetCellType() == CELLTYPE_FORMULA && p->HasRelNameReference() )
+ p->SetDirty();
+ }
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScColumn::CalcAll()
+{
+ if (pItems)
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+#if OSL_DEBUG_LEVEL > 1
+ // nach F9 ctrl-F9: ueberprueft die Berechnung per FormulaTree
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ double nOldVal, nNewVal;
+ nOldVal = pFCell->GetValue();
+#endif
+ ((ScFormulaCell*)pCell)->Interpret();
+#if OSL_DEBUG_LEVEL > 1
+ if ( pFCell->GetCode()->IsRecalcModeNormal() )
+ nNewVal = pFCell->GetValue();
+ else
+ nNewVal = nOldVal; // random(), jetzt() etc.
+ DBG_ASSERT( nOldVal==nNewVal, "CalcAll: nOldVal != nNewVal" );
+#endif
+ }
+ }
+}
+
+
+void ScColumn::CompileAll()
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ SCROW nRow = pItems[i].nRow;
+ // fuer unbedingtes kompilieren
+ // bCompile=TRUE und pCode->nError=0
+ ((ScFormulaCell*)pCell)->GetCode()->SetCodeError( 0 );
+ ((ScFormulaCell*)pCell)->SetCompile( TRUE );
+ ((ScFormulaCell*)pCell)->CompileTokenArray();
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener geloescht/eingefuegt?
+ }
+ }
+}
+
+
+void ScColumn::CompileXML( ScProgress& rProgress )
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ SCROW nRow = pItems[i].nRow;
+ ((ScFormulaCell*)pCell)->CompileXML( rProgress );
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener geloescht/eingefuegt?
+ }
+ }
+}
+
+
+void ScColumn::CalcAfterLoad()
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->CalcAfterLoad();
+ }
+}
+
+
+bool ScColumn::MarkUsedExternalReferences()
+{
+ bool bAllMarked = false;
+ if (pItems)
+ {
+ for (SCSIZE i = 0; i < nCount && !bAllMarked; ++i)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ bAllMarked = ((ScFormulaCell*)pCell)->MarkUsedExternalReferences();
+ }
+ }
+ return bAllMarked;
+}
+
+
+void ScColumn::ResetChanged( SCROW nStartRow, SCROW nEndRow )
+{
+ if (pItems)
+ {
+ SCSIZE nIndex;
+ Search(nStartRow,nIndex);
+ while (nIndex<nCount && pItems[nIndex].nRow <= nEndRow)
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ ((ScFormulaCell*)pCell)->ResetChanged();
+ ++nIndex;
+ }
+ }
+}
+
+
+BOOL ScColumn::HasEditCells(SCROW nStartRow, SCROW nEndRow, SCROW& rFirst) const
+{
+ // used in GetOptimalHeight - ambiguous script type counts as edit cell
+
+ SCROW nRow = 0;
+ SCSIZE nIndex;
+ Search(nStartRow,nIndex);
+ while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : FALSE )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_EDIT ||
+ IsAmbiguousScriptNonZero( pDocument->GetScriptType(nCol, nRow, nTab, pCell) ) )
+ {
+ rFirst = nRow;
+ return TRUE;
+ }
+ ++nIndex;
+ }
+
+ return FALSE;
+}
+
+
+SCsROW ScColumn::SearchStyle( SCsROW nRow, const ScStyleSheet* pSearchStyle,
+ BOOL bUp, BOOL bInSelection, const ScMarkData& rMark )
+{
+ if (bInSelection)
+ {
+ if (rMark.IsMultiMarked())
+ return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp,
+ (ScMarkArray*) rMark.GetArray()+nCol ); //! const
+ else
+ return -1;
+ }
+ else
+ return pAttrArray->SearchStyle( nRow, pSearchStyle, bUp, NULL );
+}
+
+
+BOOL ScColumn::SearchStyleRange( SCsROW& rRow, SCsROW& rEndRow, const ScStyleSheet* pSearchStyle,
+ BOOL bUp, BOOL bInSelection, const ScMarkData& rMark )
+{
+ if (bInSelection)
+ {
+ if (rMark.IsMultiMarked())
+ return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp,
+ (ScMarkArray*) rMark.GetArray()+nCol ); //! const
+ else
+ return FALSE;
+ }
+ else
+ return pAttrArray->SearchStyleRange( rRow, rEndRow, pSearchStyle, bUp, NULL );
+}
+
+
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
new file mode 100644
index 000000000000..97de46655741
--- /dev/null
+++ b/sc/source/core/data/column2.cxx
@@ -0,0 +1,1859 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: column2.cxx,v $
+ * $Revision: 1.32.126.6 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/eeitem.hxx>
+
+#include <svx/algitem.hxx>
+#include <svx/editobj.hxx>
+#include <svx/editstat.hxx>
+#include <svx/emphitem.hxx>
+#include <svx/fhgtitem.hxx>
+#include <svx/forbiddencharacterstable.hxx>
+#include <svx/rotmodit.hxx>
+#include <svx/scripttypeitem.hxx>
+#include <svx/unolingu.hxx>
+#include <svtools/zforlist.hxx>
+#include <svtools/broadcast.hxx>
+#include <svtools/listeneriter.hxx>
+#include <vcl/outdev.hxx>
+
+#include "column.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "docpool.hxx"
+#include "attarray.hxx"
+#include "patattr.hxx"
+#include "cellform.hxx"
+#include "collect.hxx"
+#include "stlsheet.hxx"
+#include "rechead.hxx"
+#include "brdcst.hxx"
+#include "editutil.hxx"
+#include "subtotal.hxx"
+#include "markdata.hxx"
+#include "compiler.hxx" // ScTokenArray GetCodeLen
+#include "dbcolect.hxx"
+#include "fillinfo.hxx"
+
+#include <math.h>
+
+// -----------------------------------------------------------------------
+
+// factor from font size to optimal cell height (text width)
+#define SC_ROT_BREAK_FACTOR 6
+
+// -----------------------------------------------------------------------
+
+inline BOOL IsAmbiguousScript( BYTE nScript )
+{
+ //! move to a header file
+ return ( nScript != SCRIPTTYPE_LATIN &&
+ nScript != SCRIPTTYPE_ASIAN &&
+ nScript != SCRIPTTYPE_COMPLEX );
+}
+
+// -----------------------------------------------------------------------------------------
+
+//
+// Datei-Operationen
+//
+
+// -----------------------------------------------------------------------------------------
+
+//UNUSED2008-05 SCROW ScColumn::NoteCount( SCROW nMaxRow ) const
+//UNUSED2008-05 {
+//UNUSED2008-05 SCROW nNoteCount = 0;
+//UNUSED2008-05 SCSIZE i;
+//UNUSED2008-05
+//UNUSED2008-05 for (i=0; i<nCount; i++)
+//UNUSED2008-05 if ( pItems[i].pCell->GetNotePtr() && pItems[i].nRow<=nMaxRow )
+//UNUSED2008-05 ++nNoteCount;
+//UNUSED2008-05
+//UNUSED2008-05 return nNoteCount;
+//UNUSED2008-05 }
+
+// -----------------------------------------------------------------------------------------
+
+//UNUSED2008-05 void ScColumn::CorrectSymbolCells( CharSet eStreamCharSet )
+//UNUSED2008-05 {
+//UNUSED2008-05 // #99139# find and correct string cells that are formatted with a symbol font,
+//UNUSED2008-05 // but are not in the LoadedSymbolStringCellsList
+//UNUSED2008-05 // (because CELLTYPE_SYMBOLS wasn't written in the file)
+//UNUSED2008-05
+//UNUSED2008-05 ScFontToSubsFontConverter_AutoPtr xFontConverter;
+//UNUSED2008-05 const ULONG nFontConverterFlags = FONTTOSUBSFONT_EXPORT | FONTTOSUBSFONT_ONLYOLDSOSYMBOLFONTS;
+//UNUSED2008-05
+//UNUSED2008-05 BOOL bListInitialized = FALSE;
+//UNUSED2008-05 ScSymbolStringCellEntry* pCurrentEntry = NULL;
+//UNUSED2008-05
+//UNUSED2008-05 ScAttrIterator aAttrIter( pAttrArray, 0, MAXROW );
+//UNUSED2008-05 SCROW nStt, nEnd;
+//UNUSED2008-05 const ScPatternAttr* pAttr = aAttrIter.Next( nStt, nEnd );
+//UNUSED2008-05 while ( pAttr )
+//UNUSED2008-05 {
+//UNUSED2008-05 if ( (xFontConverter = pAttr->GetSubsFontConverter( nFontConverterFlags )) ||
+//UNUSED2008-05 pAttr->IsSymbolFont() )
+//UNUSED2008-05 {
+//UNUSED2008-05 ScColumnIterator aCellIter( this, nStt, nEnd );
+//UNUSED2008-05 SCROW nRow;
+//UNUSED2008-05 ScBaseCell* pCell;
+//UNUSED2008-05 while ( aCellIter.Next( nRow, pCell ) )
+//UNUSED2008-05 {
+//UNUSED2008-05 if ( pCell->GetCellType() == CELLTYPE_STRING )
+//UNUSED2008-05 {
+//UNUSED2008-05 List& rList = pDocument->GetLoadedSymbolStringCellsList();
+//UNUSED2008-05 if (!bListInitialized)
+//UNUSED2008-05 {
+//UNUSED2008-05 pCurrentEntry = (ScSymbolStringCellEntry*)rList.First();
+//UNUSED2008-05 bListInitialized = TRUE;
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05 while ( pCurrentEntry && pCurrentEntry->nRow < nRow )
+//UNUSED2008-05 pCurrentEntry = (ScSymbolStringCellEntry*)rList.Next();
+//UNUSED2008-05
+//UNUSED2008-05 if ( pCurrentEntry && pCurrentEntry->nRow == nRow )
+//UNUSED2008-05 {
+//UNUSED2008-05 // found
+//UNUSED2008-05 }
+//UNUSED2008-05 else
+//UNUSED2008-05 {
+//UNUSED2008-05 // not in list -> convert and put into list
+//UNUSED2008-05
+//UNUSED2008-05 ScStringCell* pStrCell = (ScStringCell*)pCell;
+//UNUSED2008-05 String aOldStr;
+//UNUSED2008-05 pStrCell->GetString( aOldStr );
+//UNUSED2008-05
+//UNUSED2008-05 // convert back to stream character set (get original data)
+//UNUSED2008-05 ByteString aByteStr( aOldStr, eStreamCharSet );
+//UNUSED2008-05
+//UNUSED2008-05 // convert using symbol encoding, as for CELLTYPE_SYMBOLS cells
+//UNUSED2008-05 String aNewStr( aByteStr, RTL_TEXTENCODING_SYMBOL );
+//UNUSED2008-05 pStrCell->SetString( aNewStr );
+//UNUSED2008-05
+//UNUSED2008-05 ScSymbolStringCellEntry * pEntry = new ScSymbolStringCellEntry;
+//UNUSED2008-05 pEntry->pCell = pStrCell;
+//UNUSED2008-05 pEntry->nRow = nRow;
+//UNUSED2008-05
+//UNUSED2008-05 if ( pCurrentEntry )
+//UNUSED2008-05 rList.Insert( pEntry ); // before current entry - pCurrentEntry stays valid
+//UNUSED2008-05 else
+//UNUSED2008-05 rList.Insert( pEntry, LIST_APPEND ); // append if already behind last entry
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05 pAttr = aAttrIter.Next( nStt, nEnd );
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+
+// -----------------------------------------------------------------------------------------
+
+ // GetNeededSize: optimale Hoehe / Breite in Pixeln
+
+long ScColumn::GetNeededSize( SCROW nRow, OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bWidth, const ScNeededSizeOptions& rOptions )
+{
+ long nValue=0;
+ SCSIZE nIndex;
+ double nPPT = bWidth ? nPPTX : nPPTY;
+ if (Search(nRow,nIndex))
+ {
+ const ScPatternAttr* pPattern = rOptions.pPattern;
+ if (!pPattern)
+ pPattern = pAttrArray->GetPattern( nRow );
+
+ // zusammengefasst?
+ // Merge nicht in bedingter Formatierung
+
+ const ScMergeAttr* pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
+ const ScMergeFlagAttr* pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
+
+ if ( bWidth )
+ {
+ if ( pFlag->IsHorOverlapped() )
+ return 0;
+ if ( rOptions.bSkipMerged && pMerge->GetColMerge() > 1 )
+ return 0;
+ }
+ else
+ {
+ if ( pFlag->IsVerOverlapped() )
+ return 0;
+ if ( rOptions.bSkipMerged && pMerge->GetRowMerge() > 1 )
+ return 0;
+ }
+
+ // bedingte Formatierung
+ const SfxItemSet* pCondSet = NULL;
+ if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() )
+ pCondSet = pDocument->GetCondResult( nCol, nRow, nTab );
+
+ // Zeilenumbruch?
+
+ const SfxPoolItem* pCondItem;
+ SvxCellHorJustify eHorJust;
+ if (pCondSet &&
+ pCondSet->GetItemState(ATTR_HOR_JUSTIFY, TRUE, &pCondItem) == SFX_ITEM_SET)
+ eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem*)pCondItem)->GetValue();
+ else
+ eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
+ pPattern->GetItem( ATTR_HOR_JUSTIFY )).GetValue();
+ BOOL bBreak;
+ if ( eHorJust == SVX_HOR_JUSTIFY_BLOCK )
+ bBreak = TRUE;
+ else if ( pCondSet &&
+ pCondSet->GetItemState(ATTR_LINEBREAK, TRUE, &pCondItem) == SFX_ITEM_SET)
+ bBreak = ((const SfxBoolItem*)pCondItem)->GetValue();
+ else
+ bBreak = ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue();
+
+ // get other attributes from pattern and conditional formatting
+
+ SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
+ BOOL bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
+ ((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
+ if ( bAsianVertical )
+ bBreak = FALSE;
+
+ if ( bWidth && bBreak ) // after determining bAsianVertical (bBreak may be reset)
+ return 0;
+
+ long nRotate = 0;
+ SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
+ if ( eOrient == SVX_ORIENTATION_STANDARD )
+ {
+ if (pCondSet &&
+ pCondSet->GetItemState(ATTR_ROTATE_VALUE, TRUE, &pCondItem) == SFX_ITEM_SET)
+ nRotate = ((const SfxInt32Item*)pCondItem)->GetValue();
+ else
+ nRotate = ((const SfxInt32Item&)pPattern->GetItem(ATTR_ROTATE_VALUE)).GetValue();
+ if ( nRotate )
+ {
+ if (pCondSet &&
+ pCondSet->GetItemState(ATTR_ROTATE_MODE, TRUE, &pCondItem) == SFX_ITEM_SET)
+ eRotMode = (SvxRotateMode)((const SvxRotateModeItem*)pCondItem)->GetValue();
+ else
+ eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
+ pPattern->GetItem(ATTR_ROTATE_MODE)).GetValue();
+
+ if ( nRotate == 18000 )
+ eRotMode = SVX_ROTATE_MODE_STANDARD; // keinen Ueberlauf
+ }
+ }
+
+ if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
+ {
+ // ignore orientation/rotation if "repeat" is active
+ eOrient = SVX_ORIENTATION_STANDARD;
+ nRotate = 0;
+ bAsianVertical = FALSE;
+ }
+
+ const SvxMarginItem* pMargin;
+ if (pCondSet &&
+ pCondSet->GetItemState(ATTR_MARGIN, TRUE, &pCondItem) == SFX_ITEM_SET)
+ pMargin = (const SvxMarginItem*) pCondItem;
+ else
+ pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
+ USHORT nIndent = 0;
+ if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
+ {
+ if (pCondSet &&
+ pCondSet->GetItemState(ATTR_INDENT, TRUE, &pCondItem) == SFX_ITEM_SET)
+ nIndent = ((const SfxUInt16Item*)pCondItem)->GetValue();
+ else
+ nIndent = ((const SfxUInt16Item&)pPattern->GetItem(ATTR_INDENT)).GetValue();
+ }
+
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ BYTE nScript = pDocument->GetScriptType( nCol, nRow, nTab, pCell );
+ if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
+
+ // also call SetFont for edit cells, because bGetFont may be set only once
+ // bGetFont is set also if script type changes
+ if (rOptions.bGetFont)
+ {
+ Fraction aFontZoom = ( eOrient == SVX_ORIENTATION_STANDARD ) ? rZoomX : rZoomY;
+ Font aFont;
+ // font color doesn't matter here
+ pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &aFontZoom, pCondSet, nScript );
+ pDev->SetFont(aFont);
+ }
+
+ BOOL bAddMargin = TRUE;
+ BOOL bEditEngine = ( pCell->GetCellType() == CELLTYPE_EDIT ||
+ eOrient == SVX_ORIENTATION_STACKED ||
+ IsAmbiguousScript( nScript ) );
+
+ if (!bEditEngine) // direkte Ausgabe
+ {
+ String aValStr;
+ Color* pColor;
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+ ULONG nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
+ ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor,
+ *pFormatter,
+ TRUE, rOptions.bFormula, ftCheck );
+ if (aValStr.Len())
+ {
+ // SetFont ist nach oben verschoben
+
+ Size aSize( pDev->GetTextWidth( aValStr ), pDev->GetTextHeight() );
+ if ( eOrient != SVX_ORIENTATION_STANDARD )
+ {
+ long nTemp = aSize.Width();
+ aSize.Width() = aSize.Height();
+ aSize.Height() = nTemp;
+ }
+ else if ( nRotate )
+ {
+ //! unterschiedliche Skalierung X/Y beruecksichtigen
+
+ double nRealOrient = nRotate * F_PI18000; // nRotate sind 1/100 Grad
+ double nCosAbs = fabs( cos( nRealOrient ) );
+ double nSinAbs = fabs( sin( nRealOrient ) );
+ long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
+ long nWidth;
+ if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
+ nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
+ else if ( rOptions.bTotalSize )
+ {
+ nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
+ bAddMargin = FALSE;
+ // nur nach rechts:
+ //! unterscheiden nach Ausrichtung oben/unten (nur Text/ganze Hoehe)
+ if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
+ nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
+ nPPT * nCosAbs / nSinAbs );
+ }
+ else
+ nWidth = (long)( aSize.Height() / nSinAbs ); //! begrenzen?
+
+ if ( bBreak && !rOptions.bTotalSize )
+ {
+ // #47744# limit size for line break
+ long nCmp = pDev->GetFont().GetSize().Height() * SC_ROT_BREAK_FACTOR;
+ if ( nHeight > nCmp )
+ nHeight = nCmp;
+ }
+
+ aSize = Size( nWidth, nHeight );
+ }
+ nValue = bWidth ? aSize.Width() : aSize.Height();
+
+ if ( bAddMargin )
+ {
+ if (bWidth)
+ {
+ nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
+ (long) ( pMargin->GetRightMargin() * nPPT );
+ if ( nIndent )
+ nValue += (long) ( nIndent * nPPT );
+ }
+ else
+ nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
+ (long) ( pMargin->GetBottomMargin() * nPPT );
+ }
+
+ // Zeilenumbruch ausgefuehrt ?
+
+ if ( bBreak && !bWidth )
+ {
+ // Test mit EditEngine zur Sicherheit schon bei 90%
+ // (wegen Rundungsfehlern und weil EditEngine teilweise anders formatiert)
+
+ long nDocPixel = (long) ( ( pDocument->GetColWidth( nCol,nTab ) -
+ pMargin->GetLeftMargin() - pMargin->GetRightMargin() -
+ nIndent )
+ * nPPT );
+ nDocPixel = (nDocPixel * 9) / 10; // zur Sicherheit
+ if ( aSize.Width() > nDocPixel )
+ bEditEngine = TRUE;
+ }
+ }
+ }
+
+ if (bEditEngine)
+ {
+ // der Font wird bei !bEditEngine nicht jedesmal neu gesetzt
+ Font aOldFont = pDev->GetFont();
+
+ MapMode aHMMMode( MAP_100TH_MM, Point(), rZoomX, rZoomY );
+
+ // am Dokument speichern ?
+ ScFieldEditEngine* pEngine = pDocument->CreateFieldEditEngine();
+
+ pEngine->SetUpdateMode( FALSE );
+ MapMode aOld = pDev->GetMapMode();
+ pDev->SetMapMode( aHMMMode );
+ pEngine->SetRefDevice( pDev );
+ pEngine->SetForbiddenCharsTable( pDocument->GetForbiddenCharacters() );
+ pEngine->SetAsianCompressionMode( pDocument->GetAsianCompression() );
+ pEngine->SetKernAsianPunctuation( pDocument->GetAsianKerning() );
+ SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
+ pPattern->FillEditItemSet( pSet, pCondSet );
+
+// no longer needed, are setted with the text (is faster)
+// pEngine->SetDefaults( pSet );
+
+ if ( ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() ) {
+
+ com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
+ pEngine->SetHyphenator( xXHyphenator );
+ }
+
+ Size aPaper = Size( 1000000, 1000000 );
+ if ( eOrient==SVX_ORIENTATION_STACKED && !bAsianVertical )
+ aPaper.Width() = 1;
+ else if (bBreak)
+ {
+ double fWidthFactor = nPPTX;
+ BOOL bTextWysiwyg = ( pDev->GetOutDevType() == OUTDEV_PRINTER );
+ if ( bTextWysiwyg )
+ {
+ // #95593# if text is formatted for printer, don't use PixelToLogic,
+ // to ensure the exact same paper width (and same line breaks) as in
+ // ScEditUtil::GetEditArea, used for output.
+
+ fWidthFactor = HMM_PER_TWIPS;
+ }
+
+ // use original width for hidden columns:
+ long nDocWidth = (long) ( pDocument->GetOriginalWidth(nCol,nTab) * fWidthFactor );
+ SCCOL nColMerge = pMerge->GetColMerge();
+ if (nColMerge > 1)
+ for (SCCOL nColAdd=1; nColAdd<nColMerge; nColAdd++)
+ nDocWidth += (long) ( pDocument->GetColWidth(nCol+nColAdd,nTab) * fWidthFactor );
+ nDocWidth -= (long) ( pMargin->GetLeftMargin() * fWidthFactor )
+ + (long) ( pMargin->GetRightMargin() * fWidthFactor )
+ + 1; // Ausgabebereich ist Breite-1 Pixel (wegen Gitterlinien)
+ if ( nIndent )
+ nDocWidth -= (long) ( nIndent * fWidthFactor );
+
+ // space for AutoFilter button: 20 * nZoom/100
+ if ( pFlag->HasAutoFilter() && !bTextWysiwyg )
+ nDocWidth -= (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
+
+ aPaper.Width() = nDocWidth;
+
+ if ( !bTextWysiwyg )
+ aPaper = pDev->PixelToLogic( aPaper, aHMMMode );
+ }
+ pEngine->SetPaperSize(aPaper);
+
+ if ( pCell->GetCellType() == CELLTYPE_EDIT )
+ {
+ const EditTextObject* pData;
+ ((ScEditCell*)pCell)->GetData(pData);
+ pEngine->SetTextNewDefaults(*pData, pSet);
+ }
+ else
+ {
+ Color* pColor;
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+ ULONG nFormat = pPattern->GetNumberFormat( pFormatter, pCondSet );
+ String aString;
+ ScCellFormat::GetString( pCell, nFormat, aString, &pColor,
+ *pFormatter,
+ TRUE, rOptions.bFormula, ftCheck );
+ if (aString.Len())
+ pEngine->SetTextNewDefaults(aString, pSet);
+ else
+ pEngine->SetDefaults(pSet);
+ }
+
+ BOOL bEngineVertical = pEngine->IsVertical();
+ pEngine->SetVertical( bAsianVertical );
+ pEngine->SetUpdateMode( TRUE );
+
+ BOOL bEdWidth = bWidth;
+ if ( eOrient != SVX_ORIENTATION_STANDARD && eOrient != SVX_ORIENTATION_STACKED )
+ bEdWidth = !bEdWidth;
+ if ( nRotate )
+ {
+ //! unterschiedliche Skalierung X/Y beruecksichtigen
+
+ Size aSize( pEngine->CalcTextWidth(), pEngine->GetTextHeight() );
+ double nRealOrient = nRotate * F_PI18000; // nRotate sind 1/100 Grad
+ double nCosAbs = fabs( cos( nRealOrient ) );
+ double nSinAbs = fabs( sin( nRealOrient ) );
+ long nHeight = (long)( aSize.Height() * nCosAbs + aSize.Width() * nSinAbs );
+ long nWidth;
+ if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
+ nWidth = (long)( aSize.Width() * nCosAbs + aSize.Height() * nSinAbs );
+ else if ( rOptions.bTotalSize )
+ {
+ nWidth = (long) ( pDocument->GetColWidth( nCol,nTab ) * nPPT );
+ bAddMargin = FALSE;
+ if ( pPattern->GetRotateDir( pCondSet ) == SC_ROTDIR_RIGHT )
+ nWidth += (long)( pDocument->GetRowHeight( nRow,nTab ) *
+ nPPT * nCosAbs / nSinAbs );
+ }
+ else
+ nWidth = (long)( aSize.Height() / nSinAbs ); //! begrenzen?
+ aSize = Size( nWidth, nHeight );
+
+ Size aPixSize = pDev->LogicToPixel( aSize, aHMMMode );
+ if ( bEdWidth )
+ nValue = aPixSize.Width();
+ else
+ {
+ nValue = aPixSize.Height();
+
+ if ( bBreak && !rOptions.bTotalSize )
+ {
+ // #47744# limit size for line break
+ long nCmp = aOldFont.GetSize().Height() * SC_ROT_BREAK_FACTOR;
+ if ( nValue > nCmp )
+ nValue = nCmp;
+ }
+ }
+ }
+ else if ( bEdWidth )
+ {
+ if (bBreak)
+ nValue = 0;
+ else
+ nValue = pDev->LogicToPixel(Size( pEngine->CalcTextWidth(), 0 ),
+ aHMMMode).Width();
+ }
+ else // Hoehe
+ {
+ nValue = pDev->LogicToPixel(Size( 0, pEngine->GetTextHeight() ),
+ aHMMMode).Height();
+ }
+
+ if ( nValue && bAddMargin )
+ {
+ if (bWidth)
+ {
+ nValue += (long) ( pMargin->GetLeftMargin() * nPPT ) +
+ (long) ( pMargin->GetRightMargin() * nPPT );
+ if (nIndent)
+ nValue += (long) ( nIndent * nPPT );
+ }
+ else
+ {
+ nValue += (long) ( pMargin->GetTopMargin() * nPPT ) +
+ (long) ( pMargin->GetBottomMargin() * nPPT );
+
+ if ( bAsianVertical && pDev->GetOutDevType() != OUTDEV_PRINTER )
+ {
+ // add 1pt extra (default margin value) for line breaks with SetVertical
+ nValue += (long) ( 20 * nPPT );
+ }
+ }
+ }
+
+ // EditEngine is cached and re-used, so the old vertical flag must be restored
+ pEngine->SetVertical( bEngineVertical );
+
+ pDocument->DisposeFieldEditEngine(pEngine);
+
+ pDev->SetMapMode( aOld );
+ pDev->SetFont( aOldFont );
+ }
+
+ if (bWidth)
+ {
+ // Platz fuer Autofilter-Button
+ // 20 * nZoom/100
+ // bedingte Formatierung hier nicht interessant
+
+ INT16 nFlags = ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).GetValue();
+ if (nFlags & SC_MF_AUTO)
+ nValue += (rZoomX.GetNumerator()*20)/rZoomX.GetDenominator();
+ }
+ }
+ return nValue;
+}
+
+long ScColumn::GetSimpleTextNeededSize( SCSIZE nIndex, OutputDevice* pDev,
+ BOOL bWidth )
+{
+ long nValue=0;
+ if ( nIndex < nCount )
+ {
+ SCROW nRow = pItems[nIndex].nRow;
+ const ScPatternAttr* pPattern = pAttrArray->GetPattern( nRow );
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ String aValStr;
+ Color* pColor;
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+ ULONG nFormat = pPattern->GetNumberFormat( pFormatter );
+ ScCellFormat::GetString( pCell, nFormat, aValStr, &pColor,
+ *pFormatter, TRUE, FALSE, ftCheck );
+ if ( aValStr.Len() )
+ {
+ if ( bWidth )
+ nValue = pDev->GetTextWidth( aValStr );
+ else
+ nValue = pDev->GetTextHeight();
+ }
+ }
+ return nValue;
+}
+
+USHORT ScColumn::GetOptimalColWidth( OutputDevice* pDev, double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bFormula, USHORT nOldWidth,
+ const ScMarkData* pMarkData,
+ BOOL bSimpleTextImport )
+{
+ if (nCount == 0)
+ return nOldWidth;
+
+ USHORT nWidth = (USHORT) (nOldWidth * nPPTX);
+ BOOL bFound = FALSE;
+
+ SCSIZE nIndex;
+ ScMarkedDataIter aDataIter(this, pMarkData, TRUE);
+ if ( bSimpleTextImport )
+ { // alles eins bis auf NumberFormate
+ const ScPatternAttr* pPattern = GetPattern( 0 );
+ Font aFont;
+ // font color doesn't matter here
+ pPattern->GetFont( aFont, SC_AUTOCOL_BLACK, pDev, &rZoomX, NULL );
+ pDev->SetFont( aFont );
+ const SvxMarginItem* pMargin = (const SvxMarginItem*) &pPattern->GetItem(ATTR_MARGIN);
+ long nMargin = (long) ( pMargin->GetLeftMargin() * nPPTX ) +
+ (long) ( pMargin->GetRightMargin() * nPPTX );
+
+ while (aDataIter.Next( nIndex ))
+ {
+ USHORT nThis = (USHORT) (GetSimpleTextNeededSize( nIndex, pDev,
+ TRUE ) + nMargin);
+ if (nThis)
+ {
+ if (nThis>nWidth || !bFound)
+ {
+ nWidth = nThis;
+ bFound = TRUE;
+ }
+ }
+ }
+ }
+ else
+ {
+ ScNeededSizeOptions aOptions;
+ aOptions.bFormula = bFormula;
+ const ScPatternAttr* pOldPattern = NULL;
+ BYTE nOldScript = 0;
+
+ while (aDataIter.Next( nIndex ))
+ {
+ SCROW nRow = pItems[nIndex].nRow;
+
+ BYTE nScript = pDocument->GetScriptType( nCol, nRow, nTab, pItems[nIndex].pCell );
+ if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
+
+ const ScPatternAttr* pPattern = GetPattern( nRow );
+ aOptions.pPattern = pPattern;
+ aOptions.bGetFont = (pPattern != pOldPattern || nScript != nOldScript);
+ USHORT nThis = (USHORT) GetNeededSize( nRow, pDev, nPPTX, nPPTY,
+ rZoomX, rZoomY, TRUE, aOptions );
+ pOldPattern = pPattern;
+ if (nThis)
+ {
+ if (nThis>nWidth || !bFound)
+ {
+ nWidth = nThis;
+ bFound = TRUE;
+ }
+ }
+ }
+ }
+
+ if (bFound)
+ {
+ nWidth += 2;
+ USHORT nTwips = (USHORT) (nWidth / nPPTX);
+ return nTwips;
+ }
+ else
+ return nOldWidth;
+}
+
+USHORT lcl_GetAttribHeight( const ScPatternAttr& rPattern, USHORT nFontHeightId )
+{
+ USHORT nHeight = (USHORT) ((const SvxFontHeightItem&) rPattern.GetItem(nFontHeightId)).GetHeight();
+ const SvxMarginItem* pMargin = (const SvxMarginItem*) &rPattern.GetItem(ATTR_MARGIN);
+ nHeight += nHeight / 5;
+ // gibt bei 10pt 240
+
+ if ( ((const SvxEmphasisMarkItem&)rPattern.
+ GetItem(ATTR_FONT_EMPHASISMARK)).GetEmphasisMark() != EMPHASISMARK_NONE )
+ {
+ // add height for emphasis marks
+ //! font metrics should be used instead
+ nHeight += nHeight / 4;
+ }
+
+ if ( nHeight + 240 > ScGlobal::nDefFontHeight )
+ {
+ nHeight = sal::static_int_cast<USHORT>( nHeight + ScGlobal::nDefFontHeight );
+ nHeight -= 240;
+ }
+
+ // Standard-Hoehe: TextHeight + Raender - 23
+ // -> 257 unter Windows
+
+ if (nHeight > STD_ROWHEIGHT_DIFF)
+ nHeight -= STD_ROWHEIGHT_DIFF;
+
+ nHeight += pMargin->GetTopMargin() + pMargin->GetBottomMargin();
+
+ return nHeight;
+}
+
+// pHeight in Twips
+// nMinHeight, nMinStart zur Optimierung: ab nRow >= nMinStart ist mindestens nMinHeight
+// (wird nur bei bStdAllowed ausgewertet)
+
+void ScColumn::GetOptimalHeight( SCROW nStartRow, SCROW nEndRow, USHORT* pHeight,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bShrink, USHORT nMinHeight, SCROW nMinStart )
+{
+ ScAttrIterator aIter( pAttrArray, nStartRow, nEndRow );
+
+ SCROW nStart;
+ SCROW nEnd;
+ SCROW nEditPos = 0;
+ SCROW nNextEnd = 0;
+
+ // bei bedingter Formatierung werden immer die einzelnen Zellen angesehen
+
+ const ScPatternAttr* pPattern = aIter.Next(nStart,nEnd);
+ while ( pPattern )
+ {
+ const ScMergeAttr* pMerge = (const ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
+ const ScMergeFlagAttr* pFlag = (const ScMergeFlagAttr*)&pPattern->GetItem(ATTR_MERGE_FLAG);
+ if ( pMerge->GetRowMerge() > 1 || pFlag->IsOverlapped() )
+ {
+ // nix - vertikal bei der zusammengefassten und den ueberdeckten,
+ // horizontal nur bei den ueberdeckten (unsichtbaren) -
+ // eine nur horizontal zusammengefasste wird aber beruecksichtigt
+ }
+ else
+ {
+ SCROW nRow = 0;
+ BOOL bStdAllowed = (pPattern->GetCellOrientation() == SVX_ORIENTATION_STANDARD);
+ BOOL bStdOnly = FALSE;
+ if (bStdAllowed)
+ {
+ BOOL bBreak = ((SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK)).GetValue() ||
+ ((SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->
+ GetItem( ATTR_HOR_JUSTIFY )).GetValue() ==
+ SVX_HOR_JUSTIFY_BLOCK);
+ bStdOnly = !bBreak;
+
+ // bedingte Formatierung: Zellen durchgehen
+ if ( bStdOnly && ((const SfxUInt32Item&)pPattern->
+ GetItem(ATTR_CONDITIONAL)).GetValue() )
+ bStdOnly = FALSE;
+
+ // gedrehter Text: Zellen durchgehen
+ if ( bStdOnly && ((const SfxInt32Item&)pPattern->
+ GetItem(ATTR_ROTATE_VALUE)).GetValue() )
+ bStdOnly = FALSE;
+ }
+
+ if (bStdOnly)
+ if (HasEditCells(nStart,nEnd,nEditPos)) // includes mixed script types
+ {
+ if (nEditPos == nStart)
+ {
+ bStdOnly = FALSE;
+ if (nEnd > nEditPos)
+ nNextEnd = nEnd;
+ nEnd = nEditPos; // einzeln ausrechnen
+ bStdAllowed = FALSE; // wird auf jeden Fall per Zelle berechnet
+ }
+ else
+ {
+ nNextEnd = nEnd;
+ nEnd = nEditPos - 1; // Standard - Teil
+ }
+ }
+
+ if (bStdAllowed)
+ {
+ USHORT nLatHeight = 0;
+ USHORT nCjkHeight = 0;
+ USHORT nCtlHeight = 0;
+ USHORT nDefHeight;
+ BYTE nDefScript = ScGlobal::GetDefaultScriptType();
+ if ( nDefScript == SCRIPTTYPE_ASIAN )
+ nDefHeight = nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
+ else if ( nDefScript == SCRIPTTYPE_COMPLEX )
+ nDefHeight = nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
+ else
+ nDefHeight = nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
+
+ // if everything below is already larger, the loop doesn't have to
+ // be run again
+ SCROW nStdEnd = nEnd;
+ if ( nDefHeight <= nMinHeight && nStdEnd >= nMinStart )
+ nStdEnd = (nMinStart>0) ? nMinStart-1 : 0;
+
+ for (nRow=nStart; nRow<=nStdEnd; nRow++)
+ if (nDefHeight > pHeight[nRow-nStartRow])
+ pHeight[nRow-nStartRow] = nDefHeight;
+
+ if ( bStdOnly )
+ {
+ // if cells are not handled individually below,
+ // check for cells with different script type
+
+ SCSIZE nIndex;
+ Search(nStart,nIndex);
+ while ( nIndex < nCount && (nRow=pItems[nIndex].nRow) <= nEnd )
+ {
+ BYTE nScript = pDocument->GetScriptType( nCol, nRow, nTab, pItems[nIndex].pCell );
+ if ( nScript != nDefScript )
+ {
+ if ( nScript == SCRIPTTYPE_ASIAN )
+ {
+ if ( nCjkHeight == 0 )
+ nCjkHeight = lcl_GetAttribHeight( *pPattern, ATTR_CJK_FONT_HEIGHT );
+ if (nCjkHeight > pHeight[nRow-nStartRow])
+ pHeight[nRow-nStartRow] = nCjkHeight;
+ }
+ else if ( nScript == SCRIPTTYPE_COMPLEX )
+ {
+ if ( nCtlHeight == 0 )
+ nCtlHeight = lcl_GetAttribHeight( *pPattern, ATTR_CTL_FONT_HEIGHT );
+ if (nCtlHeight > pHeight[nRow-nStartRow])
+ pHeight[nRow-nStartRow] = nCtlHeight;
+ }
+ else
+ {
+ if ( nLatHeight == 0 )
+ nLatHeight = lcl_GetAttribHeight( *pPattern, ATTR_FONT_HEIGHT );
+ if (nLatHeight > pHeight[nRow-nStartRow])
+ pHeight[nRow-nStartRow] = nLatHeight;
+ }
+ }
+ ++nIndex;
+ }
+ }
+ }
+
+ if (!bStdOnly) // belegte Zellen suchen
+ {
+ ScNeededSizeOptions aOptions;
+
+ SCSIZE nIndex;
+ Search(nStart,nIndex);
+ while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEnd) : FALSE )
+ {
+ // Zellhoehe nur berechnen, wenn sie spaeter auch gebraucht wird (#37928#)
+
+ if ( bShrink || !(pDocument->GetRowFlags(nRow, nTab) & CR_MANUALSIZE) )
+ {
+ aOptions.pPattern = pPattern;
+ USHORT nHeight = (USHORT)
+ ( GetNeededSize( nRow, pDev, nPPTX, nPPTY,
+ rZoomX, rZoomY, FALSE, aOptions ) / nPPTY );
+ if (nHeight > pHeight[nRow-nStartRow])
+ pHeight[nRow-nStartRow] = nHeight;
+ }
+ ++nIndex;
+ }
+ }
+ }
+
+ if (nNextEnd > 0)
+ {
+ nStart = nEnd + 1;
+ nEnd = nNextEnd;
+ nNextEnd = 0;
+ }
+ else
+ pPattern = aIter.Next(nStart,nEnd);
+ }
+}
+
+BOOL ScColumn::GetNextSpellingCell(SCROW& nRow, BOOL bInSel, const ScMarkData& rData) const
+{
+ BOOL bStop = FALSE;
+ CellType eCellType;
+ SCSIZE nIndex;
+ if (!bInSel && Search(nRow, nIndex))
+ {
+ eCellType = GetCellType(nRow);
+ if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
+ !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
+ pDocument->IsTabProtected(nTab)) )
+ return TRUE;
+ }
+ while (!bStop)
+ {
+ if (bInSel)
+ {
+ nRow = rData.GetNextMarked(nCol, nRow, FALSE);
+ if (!ValidRow(nRow))
+ {
+ nRow = MAXROW+1;
+ bStop = TRUE;
+ }
+ else
+ {
+ eCellType = GetCellType(nRow);
+ if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
+ !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
+ pDocument->IsTabProtected(nTab)) )
+ return TRUE;
+ else
+ nRow++;
+ }
+ }
+ else if (GetNextDataPos(nRow))
+ {
+ eCellType = GetCellType(nRow);
+ if ( (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) &&
+ !(HasAttrib( nRow, nRow, HASATTR_PROTECTED) &&
+ pDocument->IsTabProtected(nTab)) )
+ return TRUE;
+ else
+ nRow++;
+ }
+ else
+ {
+ nRow = MAXROW+1;
+ bStop = TRUE;
+ }
+ }
+ return FALSE;
+}
+
+// =========================================================================================
+
+void ScColumn::RemoveAutoSpellObj()
+{
+ ScTabEditEngine* pEngine = NULL;
+
+ for (SCSIZE i=0; i<nCount; i++)
+ if ( pItems[i].pCell->GetCellType() == CELLTYPE_EDIT )
+ {
+ ScEditCell* pOldCell = (ScEditCell*) pItems[i].pCell;
+ const EditTextObject* pData = pOldCell->GetData();
+ // keine Abfrage auf HasOnlineSpellErrors, damit es auch
+ // nach dem Laden funktioniert
+
+ // Fuer den Test auf harte Formatierung (ScEditAttrTester) sind die Defaults
+ // in der EditEngine unwichtig. Wenn der Tester spaeter einmal gleiche
+ // Attribute in Default und harter Formatierung erkennen und weglassen sollte,
+ // muessten an der EditEngine zu jeder Zelle die richtigen Defaults gesetzt
+ // werden!
+
+ // auf Attribute testen
+ if ( !pEngine )
+ pEngine = new ScTabEditEngine(pDocument);
+ pEngine->SetText( *pData );
+ ScEditAttrTester aTester( pEngine );
+ if ( aTester.NeedsObject() ) // nur Spell-Errors entfernen
+ {
+ EditTextObject* pNewData = pEngine->CreateTextObject(); // ohne BIGOBJ
+ pOldCell->SetData( pNewData, pEngine->GetEditTextObjectPool() );
+ delete pNewData;
+ }
+ else // String erzeugen
+ {
+ String aText = ScEditUtil::GetSpaceDelimitedString( *pEngine );
+ ScBaseCell* pNewCell = new ScStringCell( aText );
+ pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() );
+ pNewCell->TakeNote( pOldCell->ReleaseNote() );
+ pItems[i].pCell = pNewCell;
+ delete pOldCell;
+ }
+ }
+
+ delete pEngine;
+}
+
+void ScColumn::RemoveEditAttribs( SCROW nStartRow, SCROW nEndRow )
+{
+ ScFieldEditEngine* pEngine = NULL;
+
+ SCSIZE i;
+ Search( nStartRow, i );
+ for (; i<nCount && pItems[i].nRow <= nEndRow; i++)
+ if ( pItems[i].pCell->GetCellType() == CELLTYPE_EDIT )
+ {
+ ScEditCell* pOldCell = (ScEditCell*) pItems[i].pCell;
+ const EditTextObject* pData = pOldCell->GetData();
+
+ // Fuer den Test auf harte Formatierung (ScEditAttrTester) sind die Defaults
+ // in der EditEngine unwichtig. Wenn der Tester spaeter einmal gleiche
+ // Attribute in Default und harter Formatierung erkennen und weglassen sollte,
+ // muessten an der EditEngine zu jeder Zelle die richtigen Defaults gesetzt
+ // werden!
+
+ // auf Attribute testen
+ if ( !pEngine )
+ {
+ //pEngine = new ScTabEditEngine(pDocument);
+ pEngine = new ScFieldEditEngine( pDocument->GetEditPool() );
+ // EE_CNTRL_ONLINESPELLING falls schon Fehler drin sind
+ pEngine->SetControlWord( pEngine->GetControlWord() | EE_CNTRL_ONLINESPELLING );
+ pEngine->SetForbiddenCharsTable( pDocument->GetForbiddenCharacters() );
+ pEngine->SetAsianCompressionMode( pDocument->GetAsianCompression() );
+ pEngine->SetKernAsianPunctuation( pDocument->GetAsianKerning() );
+ }
+ pEngine->SetText( *pData );
+ USHORT nParCount = pEngine->GetParagraphCount();
+ for (USHORT nPar=0; nPar<nParCount; nPar++)
+ {
+ pEngine->QuickRemoveCharAttribs( nPar );
+ const SfxItemSet& rOld = pEngine->GetParaAttribs( nPar );
+ if ( rOld.Count() )
+ {
+ SfxItemSet aNew( *rOld.GetPool(), rOld.GetRanges() ); // leer
+ pEngine->SetParaAttribs( nPar, aNew );
+ }
+ }
+ // URL-Felder in Text wandeln (andere gibt's nicht, darum pType=0)
+ pEngine->RemoveFields( TRUE );
+
+ BOOL bSpellErrors = pEngine->HasOnlineSpellErrors();
+ BOOL bNeedObject = bSpellErrors || nParCount>1; // Errors/Absaetze behalten
+ // ScEditAttrTester nicht mehr noetig, Felder sind raus
+
+ if ( bNeedObject ) // bleibt Edit-Zelle
+ {
+ ULONG nCtrl = pEngine->GetControlWord();
+ ULONG nWantBig = bSpellErrors ? EE_CNTRL_ALLOWBIGOBJS : 0;
+ if ( ( nCtrl & EE_CNTRL_ALLOWBIGOBJS ) != nWantBig )
+ pEngine->SetControlWord( (nCtrl & ~EE_CNTRL_ALLOWBIGOBJS) | nWantBig );
+ EditTextObject* pNewData = pEngine->CreateTextObject();
+ pOldCell->SetData( pNewData, pEngine->GetEditTextObjectPool() );
+ delete pNewData;
+ }
+ else // String erzeugen
+ {
+ String aText = ScEditUtil::GetSpaceDelimitedString( *pEngine );
+ ScBaseCell* pNewCell = new ScStringCell( aText );
+ pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() );
+ pNewCell->TakeNote( pOldCell->ReleaseNote() );
+ pItems[i].pCell = pNewCell;
+ delete pOldCell;
+ }
+ }
+
+ delete pEngine;
+}
+
+// =========================================================================================
+
+BOOL ScColumn::TestTabRefAbs(SCTAB nTable)
+{
+ BOOL bRet = FALSE;
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ if ( pItems[i].pCell->GetCellType() == CELLTYPE_FORMULA )
+ if (((ScFormulaCell*)pItems[i].pCell)->TestTabRefAbs(nTable))
+ bRet = TRUE;
+ return bRet;
+}
+
+// =========================================================================================
+
+ScColumnIterator::ScColumnIterator( const ScColumn* pCol, SCROW nStart, SCROW nEnd ) :
+ pColumn( pCol ),
+ nTop( nStart ),
+ nBottom( nEnd )
+{
+ pColumn->Search( nTop, nPos );
+}
+
+ScColumnIterator::~ScColumnIterator()
+{
+}
+
+BOOL ScColumnIterator::Next( SCROW& rRow, ScBaseCell*& rpCell )
+{
+ if ( nPos < pColumn->nCount )
+ {
+ rRow = pColumn->pItems[nPos].nRow;
+ if ( rRow <= nBottom )
+ {
+ rpCell = pColumn->pItems[nPos].pCell;
+ ++nPos;
+ return TRUE;
+ }
+ }
+
+ rRow = 0;
+ rpCell = NULL;
+ return FALSE;
+}
+
+SCSIZE ScColumnIterator::GetIndex() const // Index zur letzen abgefragten Zelle
+{
+ return nPos - 1; // bei Next ist Pos hochgezaehlt worden
+}
+
+// -----------------------------------------------------------------------------------------
+
+ScMarkedDataIter::ScMarkedDataIter( const ScColumn* pCol, const ScMarkData* pMarkData,
+ BOOL bAllIfNone ) :
+ pColumn( pCol ),
+ pMarkIter( NULL ),
+ bNext( TRUE ),
+ bAll( bAllIfNone )
+{
+ if (pMarkData && pMarkData->IsMultiMarked())
+ pMarkIter = new ScMarkArrayIter( pMarkData->GetArray() + pCol->GetCol() );
+}
+
+ScMarkedDataIter::~ScMarkedDataIter()
+{
+ delete pMarkIter;
+}
+
+BOOL ScMarkedDataIter::Next( SCSIZE& rIndex )
+{
+ BOOL bFound = FALSE;
+ do
+ {
+ if (bNext)
+ {
+ if (!pMarkIter || !pMarkIter->Next( nTop, nBottom ))
+ {
+ if (bAll) // ganze Spalte
+ {
+ nTop = 0;
+ nBottom = MAXROW;
+ }
+ else
+ return FALSE;
+ }
+ pColumn->Search( nTop, nPos );
+ bNext = FALSE;
+ bAll = FALSE; // nur beim ersten Versuch
+ }
+
+ if ( nPos >= pColumn->nCount )
+ return FALSE;
+
+ if ( pColumn->pItems[nPos].nRow <= nBottom )
+ bFound = TRUE;
+ else
+ bNext = TRUE;
+ }
+ while (!bFound);
+
+ rIndex = nPos++;
+ return TRUE;
+}
+
+USHORT ScColumn::GetErrorData( SCROW nRow ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_FORMULA :
+ return ((ScFormulaCell*)pCell)->GetErrCode();
+// break;
+ default:
+ return 0;
+ }
+ }
+ return 0;
+}
+
+//------------
+
+BOOL ScColumn::IsEmptyData() const
+{
+ return (nCount == 0);
+}
+
+BOOL ScColumn::IsEmptyVisData(BOOL bNotes) const
+{
+ if (!pItems || nCount == 0)
+ return TRUE;
+ else
+ {
+ BOOL bVisData = FALSE;
+ SCSIZE i;
+ for (i=0; i<nCount && !bVisData; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
+ bVisData = TRUE;
+ }
+ return !bVisData;
+ }
+}
+
+SCSIZE ScColumn::VisibleCount( SCROW nStartRow, SCROW nEndRow ) const
+{
+ // Notizen werden nicht mitgezaehlt
+
+ SCSIZE nVisCount = 0;
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
+ {
+ if ( pItems[nIndex].nRow >= nStartRow &&
+ pItems[nIndex].pCell->GetCellType() != CELLTYPE_NOTE )
+ {
+ ++nVisCount;
+ }
+ ++nIndex;
+ }
+ return nVisCount;
+}
+
+SCROW ScColumn::GetLastVisDataPos(BOOL bNotes) const
+{
+ SCROW nRet = 0;
+ if (pItems)
+ {
+ SCSIZE i;
+ BOOL bFound = FALSE;
+ for (i=nCount; i>0 && !bFound; )
+ {
+ --i;
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
+ {
+ bFound = TRUE;
+ nRet = pItems[i].nRow;
+ }
+ }
+ }
+ return nRet;
+}
+
+SCROW ScColumn::GetFirstVisDataPos(BOOL bNotes) const
+{
+ SCROW nRet = 0;
+ if (pItems)
+ {
+ SCSIZE i;
+ BOOL bFound = FALSE;
+ for (i=0; i<nCount && !bFound; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() != CELLTYPE_NOTE || (bNotes && pCell->HasNote()) )
+ {
+ bFound = TRUE;
+ nRet = pItems[i].nRow;
+ }
+ }
+ }
+ return nRet;
+}
+
+BOOL ScColumn::HasVisibleDataAt(SCROW nRow) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ if (!pItems[nIndex].pCell->IsBlank())
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL ScColumn::IsEmptyAttr() const
+{
+ if (pAttrArray)
+ return pAttrArray->IsEmpty();
+ else
+ return TRUE;
+}
+
+BOOL ScColumn::IsEmpty() const
+{
+ return (IsEmptyData() && IsEmptyAttr());
+}
+
+BOOL ScColumn::IsEmptyBlock(SCROW nStartRow, SCROW nEndRow, bool bIgnoreNotes) const
+{
+ if ( nCount == 0 || !pItems )
+ return TRUE;
+
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
+ {
+ if ( !pItems[nIndex].pCell->IsBlank( bIgnoreNotes ) ) // found a cell
+ return FALSE; // not empty
+ ++nIndex;
+ }
+ return TRUE; // no cell found
+}
+
+SCSIZE ScColumn::GetEmptyLinesInBlock( SCROW nStartRow, SCROW nEndRow, ScDirection eDir ) const
+{
+ SCSIZE nLines = 0;
+ BOOL bFound = FALSE;
+ SCSIZE i;
+ if (pItems && (nCount > 0))
+ {
+ if (eDir == DIR_BOTTOM)
+ {
+ i = nCount;
+ while (!bFound && (i > 0))
+ {
+ i--;
+ if ( pItems[i].nRow < nStartRow )
+ break;
+ bFound = pItems[i].nRow <= nEndRow && !pItems[i].pCell->IsBlank();
+ }
+ if (bFound)
+ nLines = static_cast<SCSIZE>(nEndRow - pItems[i].nRow);
+ else
+ nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
+ }
+ else if (eDir == DIR_TOP)
+ {
+ i = 0;
+ while (!bFound && (i < nCount))
+ {
+ if ( pItems[i].nRow > nEndRow )
+ break;
+ bFound = pItems[i].nRow >= nStartRow && !pItems[i].pCell->IsBlank();
+ i++;
+ }
+ if (bFound)
+ nLines = static_cast<SCSIZE>(pItems[i-1].nRow - nStartRow);
+ else
+ nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
+ }
+ }
+ else
+ nLines = static_cast<SCSIZE>(nEndRow - nStartRow);
+ return nLines;
+}
+
+SCROW ScColumn::GetFirstDataPos() const
+{
+ if (nCount)
+ return pItems[0].nRow;
+ else
+ return 0;
+}
+
+SCROW ScColumn::GetLastDataPos() const
+{
+ if (nCount)
+ return pItems[nCount-1].nRow;
+ else
+ return 0;
+}
+
+BOOL ScColumn::GetPrevDataPos(SCROW& rRow) const
+{
+ BOOL bFound = FALSE;
+ SCSIZE i = nCount;
+ while (!bFound && (i > 0))
+ {
+ --i;
+ bFound = (pItems[i].nRow < rRow);
+ if (bFound)
+ rRow = pItems[i].nRow;
+ }
+ return bFound;
+}
+
+BOOL ScColumn::GetNextDataPos(SCROW& rRow) const // groesser als rRow
+{
+ SCSIZE nIndex;
+ if (Search( rRow, nIndex ))
+ ++nIndex; // naechste Zelle
+
+ BOOL bMore = ( nIndex < nCount );
+ if ( bMore )
+ rRow = pItems[nIndex].nRow;
+ return bMore;
+}
+
+void ScColumn::FindDataAreaPos(SCROW& rRow, long nMovY) const
+{
+ if (!nMovY) return;
+ BOOL bForward = (nMovY>0);
+
+ SCSIZE nIndex;
+ BOOL bThere = Search(rRow, nIndex);
+ if (bThere && pItems[nIndex].pCell->IsBlank())
+ bThere = FALSE;
+
+ if (bThere)
+ {
+ SCROW nLast = rRow;
+ SCSIZE nOldIndex = nIndex;
+ if (bForward)
+ {
+ if (nIndex<nCount-1)
+ {
+ ++nIndex;
+ while (nIndex<nCount-1 && pItems[nIndex].nRow==nLast+1
+ && !pItems[nIndex].pCell->IsBlank())
+ {
+ ++nIndex;
+ ++nLast;
+ }
+ if (nIndex==nCount-1)
+ if (pItems[nIndex].nRow==nLast+1 && !pItems[nIndex].pCell->IsBlank())
+ ++nLast;
+ }
+ }
+ else
+ {
+ if (nIndex>0)
+ {
+ --nIndex;
+ while (nIndex>0 && pItems[nIndex].nRow+1==nLast
+ && !pItems[nIndex].pCell->IsBlank())
+ {
+ --nIndex;
+ --nLast;
+ }
+ if (nIndex==0)
+ if (pItems[nIndex].nRow+1==nLast && !pItems[nIndex].pCell->IsBlank())
+ --nLast;
+ }
+ }
+ if (nLast==rRow)
+ {
+ bThere = FALSE;
+ nIndex = bForward ? nOldIndex+1 : nOldIndex;
+ }
+ else
+ rRow = nLast;
+ }
+
+ if (!bThere)
+ {
+ if (bForward)
+ {
+ while (nIndex<nCount && pItems[nIndex].pCell->IsBlank())
+ ++nIndex;
+ if (nIndex<nCount)
+ rRow = pItems[nIndex].nRow;
+ else
+ rRow = MAXROW;
+ }
+ else
+ {
+ while (nIndex>0 && pItems[nIndex-1].pCell->IsBlank())
+ --nIndex;
+ if (nIndex>0)
+ rRow = pItems[nIndex-1].nRow;
+ else
+ rRow = 0;
+ }
+ }
+}
+
+BOOL ScColumn::HasDataAt(SCROW nRow) const
+{
+/* SCSIZE nIndex;
+ return Search( nRow, nIndex );
+*/
+ // immer nur sichtbare interessant ?
+ //! dann HasVisibleDataAt raus
+
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ if (!pItems[nIndex].pCell->IsBlank())
+ return TRUE;
+
+ return FALSE;
+
+}
+
+BOOL ScColumn::IsAllAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
+{
+ if (pAttrArray && rCol.pAttrArray)
+ return pAttrArray->IsAllEqual( *rCol.pAttrArray, nStartRow, nEndRow );
+ else
+ return !pAttrArray && !rCol.pAttrArray;
+}
+
+BOOL ScColumn::IsVisibleAttrEqual( const ScColumn& rCol, SCROW nStartRow, SCROW nEndRow ) const
+{
+ if (pAttrArray && rCol.pAttrArray)
+ return pAttrArray->IsVisibleEqual( *rCol.pAttrArray, nStartRow, nEndRow );
+ else
+ return !pAttrArray && !rCol.pAttrArray;
+}
+
+BOOL ScColumn::GetFirstVisibleAttr( SCROW& rFirstRow ) const
+{
+ if (pAttrArray)
+ return pAttrArray->GetFirstVisibleAttr( rFirstRow );
+ else
+ return FALSE;
+}
+
+BOOL ScColumn::GetLastVisibleAttr( SCROW& rLastRow ) const
+{
+ if (pAttrArray)
+ {
+ // row of last cell is needed
+ SCROW nLastData = GetLastVisDataPos( TRUE ); // always including notes, 0 if none
+
+ return pAttrArray->GetLastVisibleAttr( rLastRow, nLastData );
+ }
+ else
+ return FALSE;
+}
+
+BOOL ScColumn::HasVisibleAttrIn( SCROW nStartRow, SCROW nEndRow ) const
+{
+ if (pAttrArray)
+ return pAttrArray->HasVisibleAttrIn( nStartRow, nEndRow );
+ else
+ return FALSE;
+}
+
+void ScColumn::FindUsed( SCROW nStartRow, SCROW nEndRow, BOOL* pUsed ) const
+{
+ SCROW nRow = 0;
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : FALSE )
+ {
+ pUsed[nRow-nStartRow] = TRUE;
+ ++nIndex;
+ }
+}
+
+void ScColumn::StartListening( SvtListener& rLst, SCROW nRow )
+{
+ SvtBroadcaster* pBC = NULL;
+ ScBaseCell* pCell;
+
+ SCSIZE nIndex;
+ if (Search(nRow,nIndex))
+ {
+ pCell = pItems[nIndex].pCell;
+ pBC = pCell->GetBroadcaster();
+ }
+ else
+ {
+ pCell = new ScNoteCell;
+ Insert(nRow, pCell);
+ }
+
+ if (!pBC)
+ {
+ pBC = new SvtBroadcaster;
+ pCell->TakeBroadcaster(pBC);
+ }
+ rLst.StartListening(*pBC);
+}
+
+void ScColumn::MoveListeners( SvtBroadcaster& rSource, SCROW nDestRow )
+{
+ SvtBroadcaster* pBC = NULL;
+ ScBaseCell* pCell;
+
+ SCSIZE nIndex;
+ if (Search(nDestRow,nIndex))
+ {
+ pCell = pItems[nIndex].pCell;
+ pBC = pCell->GetBroadcaster();
+ }
+ else
+ {
+ pCell = new ScNoteCell;
+ Insert(nDestRow, pCell);
+ }
+
+ if (!pBC)
+ {
+ pBC = new SvtBroadcaster;
+ pCell->TakeBroadcaster(pBC);
+ }
+
+ if (rSource.HasListeners())
+ {
+ SvtListenerIter aIter( rSource);
+ for (SvtListener* pLst = aIter.GoStart(); pLst; pLst = aIter.GoNext())
+ {
+ pLst->StartListening( *pBC);
+ pLst->EndListening( rSource);
+ }
+ }
+}
+
+void ScColumn::EndListening( SvtListener& rLst, SCROW nRow )
+{
+ SCSIZE nIndex;
+ if (Search(nRow,nIndex))
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ SvtBroadcaster* pBC = pCell->GetBroadcaster();
+ if (pBC)
+ {
+ rLst.EndListening(*pBC);
+
+ if (!pBC->HasListeners())
+ {
+ if (pCell->IsBlank())
+ DeleteAtIndex(nIndex);
+ else
+ pCell->DeleteBroadcaster();
+ }
+ }
+// else
+// DBG_ERROR("ScColumn::EndListening - kein Broadcaster");
+ }
+// else
+// DBG_ERROR("ScColumn::EndListening - keine Zelle");
+}
+
+void ScColumn::CompileDBFormula()
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*) pCell)->CompileDBFormula();
+ }
+}
+
+void ScColumn::CompileDBFormula( BOOL bCreateFormulaString )
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*) pCell)->CompileDBFormula( bCreateFormulaString );
+ }
+}
+
+void ScColumn::CompileNameFormula( BOOL bCreateFormulaString )
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*) pCell)->CompileNameFormula( bCreateFormulaString );
+ }
+}
+
+void ScColumn::CompileColRowNameFormula()
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*) pCell)->CompileColRowNameFormula();
+ }
+}
+
+void lcl_UpdateSubTotal( ScFunctionData& rData, ScBaseCell* pCell )
+{
+ double nValue = 0.0;
+ BOOL bVal = FALSE;
+ BOOL bCell = TRUE;
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ nValue = ((ScValueCell*)pCell)->GetValue();
+ bVal = TRUE;
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ if ( rData.eFunc != SUBTOTAL_FUNC_CNT2 ) // da interessiert's nicht
+ {
+ ScFormulaCell* pFC = (ScFormulaCell*)pCell;
+ if ( pFC->GetErrCode() )
+ {
+ if ( rData.eFunc != SUBTOTAL_FUNC_CNT ) // fuer Anzahl einfach weglassen
+ rData.bError = TRUE;
+ }
+ else if (pFC->IsValue())
+ {
+ nValue = pFC->GetValue();
+ bVal = TRUE;
+ }
+ // sonst Text
+ }
+ }
+ break;
+ case CELLTYPE_NOTE:
+ bCell = FALSE;
+ break;
+ // bei Strings nichts
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (!rData.bError)
+ {
+ switch (rData.eFunc)
+ {
+ case SUBTOTAL_FUNC_SUM:
+ case SUBTOTAL_FUNC_AVE:
+ if (bVal)
+ {
+ ++rData.nCount;
+ if (!SubTotal::SafePlus( rData.nVal, nValue ))
+ rData.bError = TRUE;
+ }
+ break;
+ case SUBTOTAL_FUNC_CNT: // nur Werte
+ if (bVal)
+ ++rData.nCount;
+ break;
+ case SUBTOTAL_FUNC_CNT2: // alle
+ if (bCell)
+ ++rData.nCount;
+ break;
+ case SUBTOTAL_FUNC_MAX:
+ if (bVal)
+ if (++rData.nCount == 1 || nValue > rData.nVal )
+ rData.nVal = nValue;
+ break;
+ case SUBTOTAL_FUNC_MIN:
+ if (bVal)
+ if (++rData.nCount == 1 || nValue < rData.nVal )
+ rData.nVal = nValue;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+}
+
+// Mehrfachselektion:
+void ScColumn::UpdateSelectionFunction( const ScMarkData& rMark,
+ ScFunctionData& rData,
+ const ScBitMaskCompressedArray< SCROW, BYTE>* pRowFlags,
+ BOOL bDoExclude, SCROW nExStartRow, SCROW nExEndRow )
+{
+ SCSIZE nIndex;
+ ScMarkedDataIter aDataIter(this, &rMark, FALSE);
+ while (aDataIter.Next( nIndex ))
+ {
+ SCROW nRow = pItems[nIndex].nRow;
+ if ( !pRowFlags || !( pRowFlags->GetValue(nRow) & CR_HIDDEN ) )
+ if ( !bDoExclude || nRow < nExStartRow || nRow > nExEndRow )
+ lcl_UpdateSubTotal( rData, pItems[nIndex].pCell );
+ }
+}
+
+// bei bNoMarked die Mehrfachselektion weglassen
+void ScColumn::UpdateAreaFunction( ScFunctionData& rData,
+ const ScBitMaskCompressedArray< SCROW, BYTE>* pRowFlags,
+ SCROW nStartRow, SCROW nEndRow )
+{
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ while ( nIndex<nCount && pItems[nIndex].nRow<=nEndRow )
+ {
+ SCROW nRow = pItems[nIndex].nRow;
+ if ( !pRowFlags || !( pRowFlags->GetValue(nRow) & CR_HIDDEN ) )
+ lcl_UpdateSubTotal( rData, pItems[nIndex].pCell );
+ ++nIndex;
+ }
+}
+
+ULONG ScColumn::GetWeightedCount() const
+{
+ ULONG nTotal = 0;
+
+ // Notizen werden nicht gezaehlt
+
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE:
+ case CELLTYPE_STRING:
+ ++nTotal;
+ break;
+ case CELLTYPE_FORMULA:
+ nTotal += 5 + ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen();
+ break;
+ case CELLTYPE_EDIT:
+ nTotal += 50;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+
+ return nTotal;
+}
+
+ULONG ScColumn::GetCodeCount() const
+{
+ ULONG nCodeCount = 0;
+
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ nCodeCount += ((ScFormulaCell*)pCell)->GetCode()->GetCodeLen();
+ }
+
+ return nCodeCount;
+}
+
+
+
+
+
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
new file mode 100644
index 000000000000..793229116fe2
--- /dev/null
+++ b/sc/source/core/data/column3.cxx
@@ -0,0 +1,1878 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: column3.cxx,v $
+ * $Revision: 1.27.128.7 $
+ *
+ * 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 ---------------------------------------------------------------
+
+
+
+#include <sfx2/objsh.hxx>
+#include <svtools/zforlist.hxx>
+#include <svtools/zformat.hxx>
+
+#include "scitems.hxx"
+#include "column.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "attarray.hxx"
+#include "patattr.hxx"
+#include "cellform.hxx"
+#include "collect.hxx"
+#include "formula/errorcodes.hxx"
+#include "formula/token.hxx"
+#include "brdcst.hxx"
+#include "docoptio.hxx" // GetStdPrecision fuer GetMaxNumberStringLen
+#include "subtotal.hxx"
+#include "markdata.hxx"
+#include "detfunc.hxx" // fuer Notizen bei DeleteRange
+#include "postit.hxx"
+
+// Err527 Workaround
+extern const ScFormulaCell* pLastFormulaTreeTop; // in cellform.cxx
+using namespace formula;
+// STATIC DATA -----------------------------------------------------------
+
+BOOL ScColumn::bDoubleAlloc = FALSE; // fuer Import: Groesse beim Allozieren verdoppeln
+
+
+void ScColumn::Insert( SCROW nRow, ScBaseCell* pNewCell )
+{
+ BOOL bIsAppended = FALSE;
+ if (pItems && nCount>0)
+ {
+ if (pItems[nCount-1].nRow < nRow)
+ {
+ Append(nRow, pNewCell );
+ bIsAppended = TRUE;
+ }
+ }
+ if ( !bIsAppended )
+ {
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ {
+ ScBaseCell* pOldCell = pItems[nIndex].pCell;
+
+ // move broadcaster and note to new cell, if not existing in new cell
+ if (pOldCell->HasBroadcaster() && !pNewCell->HasBroadcaster())
+ pNewCell->TakeBroadcaster( pOldCell->ReleaseBroadcaster() );
+ if (pOldCell->HasNote() && !pNewCell->HasNote())
+ pNewCell->TakeNote( pOldCell->ReleaseNote() );
+
+ if ( pOldCell->GetCellType() == CELLTYPE_FORMULA && !pDocument->IsClipOrUndo() )
+ {
+ pOldCell->EndListeningTo( pDocument );
+ // falls in EndListening NoteCell in gleicher Col zerstoert
+ if ( nIndex >= nCount || pItems[nIndex].nRow != nRow )
+ Search(nRow, nIndex);
+ }
+ pOldCell->Delete();
+ pItems[nIndex].pCell = pNewCell;
+ }
+ else
+ {
+ if (nCount + 1 > nLimit)
+ {
+ if (bDoubleAlloc)
+ {
+ if (nLimit < COLUMN_DELTA)
+ nLimit = COLUMN_DELTA;
+ else
+ {
+ nLimit *= 2;
+ if ( nLimit > sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
+ nLimit = MAXROWCOUNT;
+ }
+ }
+ else
+ nLimit += COLUMN_DELTA;
+
+ ColEntry* pNewItems = new ColEntry[nLimit];
+ if (pItems)
+ {
+ memmove( pNewItems, pItems, nCount * sizeof(ColEntry) );
+ delete[] pItems;
+ }
+ pItems = pNewItems;
+ }
+ memmove( &pItems[nIndex + 1], &pItems[nIndex], (nCount - nIndex) * sizeof(ColEntry) );
+ pItems[nIndex].pCell = pNewCell;
+ pItems[nIndex].nRow = nRow;
+ ++nCount;
+ }
+ }
+ // Bei aus Clipboard sind hier noch falsche (alte) Referenzen!
+ // Werden in CopyBlockFromClip per UpdateReference umgesetzt,
+ // danach StartListeningFromClip und BroadcastFromClip gerufen.
+ // Wird ins Clipboard/UndoDoc gestellt, wird kein Broadcast gebraucht.
+ // Nach Import wird CalcAfterLoad gerufen, dort Listening.
+ if ( !(pDocument->IsClipOrUndo() || pDocument->IsInsertingFromOtherDoc()) )
+ {
+ pNewCell->StartListeningTo( pDocument );
+ CellType eCellType = pNewCell->GetCellType();
+ // Notizzelle entsteht beim Laden nur durch StartListeningCell,
+ // ausloesende Formelzelle muss sowieso dirty sein.
+ if ( !(pDocument->IsCalcingAfterLoad() && eCellType == CELLTYPE_NOTE) )
+ {
+ if ( eCellType == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pNewCell)->SetDirty();
+ else
+ pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED,
+ ScAddress( nCol, nRow, nTab ), pNewCell ) );
+ }
+ }
+}
+
+
+void ScColumn::Insert( SCROW nRow, ULONG nNumberFormat, ScBaseCell* pCell )
+{
+ Insert(nRow, pCell);
+ short eOldType = pDocument->GetFormatTable()->
+ GetType( (ULONG)
+ ((SfxUInt32Item*)GetAttr( nRow, ATTR_VALUE_FORMAT ))->
+ GetValue() );
+ short eNewType = pDocument->GetFormatTable()->GetType(nNumberFormat);
+ if (!pDocument->GetFormatTable()->IsCompatible(eOldType, eNewType))
+ ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT, (UINT32) nNumberFormat) );
+}
+
+
+void ScColumn::Append( SCROW nRow, ScBaseCell* pCell )
+{
+ if (nCount + 1 > nLimit)
+ {
+ if (bDoubleAlloc)
+ {
+ if (nLimit < COLUMN_DELTA)
+ nLimit = COLUMN_DELTA;
+ else
+ {
+ nLimit *= 2;
+ if ( nLimit > sal::static_int_cast<SCSIZE>(MAXROWCOUNT) )
+ nLimit = MAXROWCOUNT;
+ }
+ }
+ else
+ nLimit += COLUMN_DELTA;
+
+ ColEntry* pNewItems = new ColEntry[nLimit];
+ if (pItems)
+ {
+ memmove( pNewItems, pItems, nCount * sizeof(ColEntry) );
+ delete[] pItems;
+ }
+ pItems = pNewItems;
+ }
+ pItems[nCount].pCell = pCell;
+ pItems[nCount].nRow = nRow;
+ ++nCount;
+}
+
+
+void ScColumn::Delete( SCROW nRow )
+{
+ SCSIZE nIndex;
+
+ if (Search(nRow, nIndex))
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ ScNoteCell* pNoteCell = new ScNoteCell;
+ pItems[nIndex].pCell = pNoteCell; // Dummy fuer Interpret
+ pDocument->Broadcast( ScHint( SC_HINT_DYING,
+ ScAddress( nCol, nRow, nTab ), pCell ) );
+ if ( SvtBroadcaster* pBC = pCell->ReleaseBroadcaster() )
+ {
+ pNoteCell->TakeBroadcaster( pBC );
+ }
+ else
+ {
+ delete pNoteCell;
+ --nCount;
+ memmove( &pItems[nIndex], &pItems[nIndex + 1], (nCount - nIndex) * sizeof(ColEntry) );
+ pItems[nCount].nRow = 0;
+ pItems[nCount].pCell = NULL;
+ // Soll man hier den Speicher freigeben (delta)? Wird dann langsamer!
+ }
+ pCell->EndListeningTo( pDocument );
+ pCell->Delete();
+ }
+}
+
+
+void ScColumn::DeleteAtIndex( SCSIZE nIndex )
+{
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ ScNoteCell* pNoteCell = new ScNoteCell;
+ pItems[nIndex].pCell = pNoteCell; // Dummy fuer Interpret
+ pDocument->Broadcast( ScHint( SC_HINT_DYING,
+ ScAddress( nCol, pItems[nIndex].nRow, nTab ), pCell ) );
+ delete pNoteCell;
+ --nCount;
+ memmove( &pItems[nIndex], &pItems[nIndex + 1], (nCount - nIndex) * sizeof(ColEntry) );
+ pItems[nCount].nRow = 0;
+ pItems[nCount].pCell = NULL;
+ pCell->EndListeningTo( pDocument );
+ pCell->Delete();
+}
+
+
+void ScColumn::FreeAll()
+{
+ if (pItems)
+ {
+ for (SCSIZE i = 0; i < nCount; i++)
+ pItems[i].pCell->Delete();
+ delete[] pItems;
+ pItems = NULL;
+ }
+ nCount = 0;
+ nLimit = 0;
+}
+
+
+void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
+{
+ pAttrArray->DeleteRow( nStartRow, nSize );
+
+ if ( !pItems || !nCount )
+ return ;
+
+ SCSIZE nFirstIndex;
+ Search( nStartRow, nFirstIndex );
+ if ( nFirstIndex >= nCount )
+ return ;
+
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+
+ BOOL bFound=FALSE;
+ SCROW nEndRow = nStartRow + nSize - 1;
+ SCSIZE nStartIndex = 0;
+ SCSIZE nEndIndex = 0;
+ SCSIZE i;
+
+ for ( i = nFirstIndex; i < nCount && pItems[i].nRow <= nEndRow; i++ )
+ {
+ if (!bFound)
+ {
+ nStartIndex = i;
+ bFound = TRUE;
+ }
+ nEndIndex = i;
+
+ ScBaseCell* pCell = pItems[i].pCell;
+ SvtBroadcaster* pBC = pCell->GetBroadcaster();
+ if (pBC)
+ {
+// gibt jetzt invalid reference, kein Aufruecken der direkten Referenzen
+// MoveListeners( *pBC, nRow+nSize );
+ pCell->DeleteBroadcaster();
+ // in DeleteRange werden leere Broadcaster geloescht
+ }
+ }
+ if (bFound)
+ {
+ DeleteRange( nStartIndex, nEndIndex, IDF_CONTENTS );
+ Search( nStartRow, i );
+ if ( i >= nCount )
+ {
+ pDocument->SetAutoCalc( bOldAutoCalc );
+ return ;
+ }
+ }
+ else
+ i = nFirstIndex;
+
+ ScAddress aAdr( nCol, 0, nTab );
+ ScHint aHint( SC_HINT_DATACHANGED, aAdr, NULL ); // only areas (ScBaseCell* == NULL)
+ ScAddress& rAddress = aHint.GetAddress();
+ // for sparse occupation use single broadcasts, not ranges
+ BOOL bSingleBroadcasts = (((pItems[nCount-1].nRow - pItems[i].nRow) /
+ (nCount - i)) > 1);
+ if ( bSingleBroadcasts )
+ {
+ SCROW nLastBroadcast = MAXROW+1;
+ for ( ; i < nCount; i++ )
+ {
+ SCROW nOldRow = pItems[i].nRow;
+ // #43940# Aenderung Quelle broadcasten
+ rAddress.SetRow( nOldRow );
+ pDocument->AreaBroadcast( aHint );
+ SCROW nNewRow = (pItems[i].nRow -= nSize);
+ // #43940# Aenderung Ziel broadcasten
+ if ( nLastBroadcast != nNewRow )
+ { // direkt aufeinanderfolgende nicht doppelt broadcasten
+ rAddress.SetRow( nNewRow );
+ pDocument->AreaBroadcast( aHint );
+ }
+ nLastBroadcast = nOldRow;
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
+ }
+ }
+ else
+ {
+ rAddress.SetRow( pItems[i].nRow );
+ ScRange aRange( rAddress );
+ aRange.aEnd.SetRow( pItems[nCount-1].nRow );
+ for ( ; i < nCount; i++ )
+ {
+ SCROW nNewRow = (pItems[i].nRow -= nSize);
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->aPos.SetRow( nNewRow );
+ }
+ pDocument->AreaBroadcastInRange( aRange, aHint );
+ }
+
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScColumn::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex, USHORT nDelFlag )
+{
+ /* If caller specifies to not remove the note caption objects, all cells
+ have to forget the pointers to them. This is used e.g. while undoing a
+ "paste cells" operation, which removes the caption objects later in
+ drawing undo. */
+ bool bDeleteNote = (nDelFlag & IDF_NOTE) != 0;
+ bool bNoCaptions = (nDelFlag & IDF_NOCAPTIONS) != 0;
+ if (bDeleteNote && bNoCaptions)
+ for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx )
+ if ( ScPostIt* pNote = pItems[ nIdx ].pCell->GetNote() )
+ pNote->ForgetCaption();
+
+ // special simple mode if all contents are deleted and cells do not contain broadcasters
+ bool bSimple = ((nDelFlag & IDF_CONTENTS) == IDF_CONTENTS);
+ if (bSimple)
+ for ( SCSIZE nIdx = nStartIndex; bSimple && (nIdx <= nEndIndex); ++nIdx )
+ if (pItems[ nIdx ].pCell->GetBroadcaster())
+ bSimple = false;
+
+ ScHint aHint( SC_HINT_DYING, ScAddress( nCol, 0, nTab ), 0 );
+
+ // cache all formula cells, they will be deleted at end of this function
+ typedef ::std::vector< ScFormulaCell* > FormulaCellVector;
+ FormulaCellVector aDelCells;
+ aDelCells.reserve( nEndIndex - nStartIndex + 1 );
+
+ // simple deletion of the cell objects
+ if (bSimple)
+ {
+ // pNoteCell: dummy replacement for old cells, to prevent that interpreter uses old cell
+ ScNoteCell* pNoteCell = new ScNoteCell;
+ for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx )
+ {
+ ScBaseCell* pOldCell = pItems[ nIdx ].pCell;
+ if (pOldCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ // cache formula cell, will be deleted below
+ aDelCells.push_back( static_cast< ScFormulaCell* >( pOldCell ) );
+ }
+ else
+ {
+ // interpret in broadcast must not use the old cell
+ pItems[ nIdx ].pCell = pNoteCell;
+ aHint.GetAddress().SetRow( pItems[ nIdx ].nRow );
+ aHint.SetCell( pOldCell );
+ pDocument->Broadcast( aHint );
+ pOldCell->Delete();
+ }
+ }
+ delete pNoteCell;
+ memmove( &pItems[nStartIndex], &pItems[nEndIndex + 1], (nCount - nEndIndex - 1) * sizeof(ColEntry) );
+ nCount -= nEndIndex-nStartIndex+1;
+ }
+
+ // else: delete some contents of the cells
+ else
+ {
+ SCSIZE j = nStartIndex;
+ for ( SCSIZE nIdx = nStartIndex; nIdx <= nEndIndex; ++nIdx )
+ {
+ // decide whether to delete the cell object according to passed flags
+ bool bDelete = false;
+ ScBaseCell* pOldCell = pItems[j].pCell;
+ CellType eCellType = pOldCell->GetCellType();
+ switch ( eCellType )
+ {
+ case CELLTYPE_VALUE:
+ {
+ USHORT nValFlags = nDelFlag & (IDF_DATETIME|IDF_VALUE);
+ // delete values and dates?
+ bDelete = nValFlags == (IDF_DATETIME|IDF_VALUE);
+ // if not, decide according to cell number format
+ if( !bDelete && (nValFlags != 0) )
+ {
+ ULONG nIndex = (ULONG)((SfxUInt32Item*)GetAttr( pItems[j].nRow, ATTR_VALUE_FORMAT ))->GetValue();
+ short nType = pDocument->GetFormatTable()->GetType(nIndex);
+ bool bIsDate = (nType == NUMBERFORMAT_DATE) || (nType == NUMBERFORMAT_TIME) || (nType == NUMBERFORMAT_DATETIME);
+ bDelete = nValFlags == (bIsDate ? IDF_DATETIME : IDF_VALUE);
+ }
+ }
+ break;
+
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ bDelete = (nDelFlag & IDF_STRING) != 0;
+ break;
+
+ case CELLTYPE_FORMULA:
+ bDelete = (nDelFlag & IDF_FORMULA) != 0;
+ break;
+
+ case CELLTYPE_NOTE:
+ // do note delete note cell with broadcaster
+ bDelete = bDeleteNote && !pOldCell->GetBroadcaster();
+ break;
+
+ default:; // added to avoid warnings
+ }
+
+ if (bDelete)
+ {
+ // try to create a replacement note cell, if note or broadcaster exists
+ ScNoteCell* pNoteCell = 0;
+ if (eCellType != CELLTYPE_NOTE)
+ {
+ // do not rescue note if it has to be deleted according to passed flags
+ ScPostIt* pNote = bDeleteNote ? 0 : pOldCell->ReleaseNote();
+ // #i99844# do not release broadcaster from old cell, it still has to notify deleted content
+ SvtBroadcaster* pBC = pOldCell->GetBroadcaster();
+ if( pNote || pBC )
+ pNoteCell = new ScNoteCell( pNote, pBC );
+ }
+
+ // remove cell entry in cell item list
+ SCROW nOldRow = pItems[j].nRow;
+ if (pNoteCell)
+ {
+ // replace old cell with the replacement note cell
+ pItems[j].pCell = pNoteCell;
+ ++j;
+ }
+ else
+ {
+ // remove the old cell from the cell item list
+ --nCount;
+ memmove( &pItems[j], &pItems[j + 1], (nCount - j) * sizeof(ColEntry) );
+ pItems[nCount].nRow = 0;
+ pItems[nCount].pCell = 0;
+ }
+
+ // cache formula cells (will be deleted later), delete cell of other type
+ if (eCellType == CELLTYPE_FORMULA)
+ {
+ aDelCells.push_back( static_cast< ScFormulaCell* >( pOldCell ) );
+ }
+ else
+ {
+ aHint.GetAddress().SetRow( nOldRow );
+ aHint.SetCell( pOldCell );
+ pDocument->Broadcast( aHint );
+ // #i99844# after broadcasting, old cell has to forget the broadcaster (owned by pNoteCell)
+ pOldCell->ReleaseBroadcaster();
+ pOldCell->Delete();
+ }
+ }
+ else
+ {
+ // delete cell note
+ if (bDeleteNote)
+ pItems[j].pCell->DeleteNote();
+ // cell not deleted, move index to next cell
+ ++j;
+ }
+ }
+ }
+
+ // *** delete all formula cells ***
+
+ // first, all cells stop listening, may save unneeded recalcualtions
+ for ( FormulaCellVector::iterator aIt = aDelCells.begin(), aEnd = aDelCells.end(); aIt != aEnd; ++aIt )
+ (*aIt)->EndListeningTo( pDocument );
+
+ // broadcast SC_HINT_DYING for all cells and delete them
+ for ( FormulaCellVector::iterator aIt = aDelCells.begin(), aEnd = aDelCells.end(); aIt != aEnd; ++aIt )
+ {
+ aHint.SetAddress( (*aIt)->aPos );
+ aHint.SetCell( *aIt );
+ pDocument->Broadcast( aHint );
+ // #i99844# after broadcasting, old cell has to forget the broadcaster (owned by replacement note cell)
+ (*aIt)->ReleaseBroadcaster();
+ (*aIt)->Delete();
+ }
+}
+
+
+void ScColumn::DeleteArea(SCROW nStartRow, SCROW nEndRow, USHORT nDelFlag)
+{
+ // FreeAll darf hier nicht gerufen werden wegen Broadcastern
+
+ // Attribute erst am Ende, damit vorher noch zwischen Zahlen und Datum
+ // unterschieden werden kann (#47901#)
+
+ USHORT nContMask = IDF_CONTENTS;
+ // IDF_NOCAPTIONS needs to be passed too, if IDF_NOTE is set
+ if( nDelFlag & IDF_NOTE )
+ nContMask |= IDF_NOCAPTIONS;
+ USHORT nContFlag = nDelFlag & nContMask;
+
+ if (pItems && nCount>0 && nContFlag)
+ {
+ if (nStartRow==0 && nEndRow==MAXROW)
+ DeleteRange( 0, nCount-1, nContFlag );
+ else
+ {
+ BOOL bFound=FALSE;
+ SCSIZE nStartIndex = 0;
+ SCSIZE nEndIndex = 0;
+ for (SCSIZE i = 0; i < nCount; i++)
+ if ((pItems[i].nRow >= nStartRow) && (pItems[i].nRow <= nEndRow))
+ {
+ if (!bFound)
+ {
+ nStartIndex = i;
+ bFound = TRUE;
+ }
+ nEndIndex = i;
+ }
+ if (bFound)
+ DeleteRange( nStartIndex, nEndIndex, nContFlag );
+ }
+ }
+
+ if ( nDelFlag & IDF_EDITATTR )
+ {
+ DBG_ASSERT( nContFlag == 0, "DeleteArea: falsche Flags" );
+ RemoveEditAttribs( nStartRow, nEndRow );
+ }
+
+ // Attribute erst hier
+ if ((nDelFlag & IDF_ATTRIB) == IDF_ATTRIB) pAttrArray->DeleteArea( nStartRow, nEndRow );
+ else if ((nDelFlag & IDF_ATTRIB) != 0) pAttrArray->DeleteHardAttr( nStartRow, nEndRow );
+}
+
+
+ScFormulaCell* ScColumn::CreateRefCell( ScDocument* pDestDoc, const ScAddress& rDestPos,
+ SCSIZE nIndex, USHORT nFlags ) const
+{
+ USHORT nContFlags = nFlags & IDF_CONTENTS;
+ if (!nContFlags)
+ return NULL;
+
+ // Testen, ob Zelle kopiert werden soll
+ // auch bei IDF_CONTENTS komplett, wegen Notes / Broadcastern
+
+ BOOL bMatch = FALSE;
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ CellType eCellType = pCell->GetCellType();
+ switch ( eCellType )
+ {
+ case CELLTYPE_VALUE:
+ {
+ USHORT nValFlags = nFlags & (IDF_DATETIME|IDF_VALUE);
+
+ if ( nValFlags == (IDF_DATETIME|IDF_VALUE) )
+ bMatch = TRUE;
+ else if ( nValFlags )
+ {
+ ULONG nNumIndex = (ULONG)((SfxUInt32Item*)GetAttr(
+ pItems[nIndex].nRow, ATTR_VALUE_FORMAT ))->GetValue();
+ short nTyp = pDocument->GetFormatTable()->GetType(nNumIndex);
+ if ((nTyp == NUMBERFORMAT_DATE) || (nTyp == NUMBERFORMAT_TIME) || (nTyp == NUMBERFORMAT_DATETIME))
+ bMatch = ((nFlags & IDF_DATETIME) != 0);
+ else
+ bMatch = ((nFlags & IDF_VALUE) != 0);
+ }
+ }
+ break;
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT: bMatch = ((nFlags & IDF_STRING) != 0); break;
+ case CELLTYPE_FORMULA: bMatch = ((nFlags & IDF_FORMULA) != 0); break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ if (!bMatch)
+ return NULL;
+
+
+ // Referenz einsetzen
+ ScSingleRefData aRef;
+ aRef.nCol = nCol;
+ aRef.nRow = pItems[nIndex].nRow;
+ aRef.nTab = nTab;
+ aRef.InitFlags(); // -> alles absolut
+ aRef.SetFlag3D(TRUE);
+
+ //! 3D(FALSE) und TabRel(TRUE), wenn die endgueltige Position auf der selben Tabelle ist?
+ //! (bei TransposeClip ist die Zielposition noch nicht bekannt)
+
+ aRef.CalcRelFromAbs( rDestPos );
+
+ ScTokenArray aArr;
+ aArr.AddSingleReference( aRef );
+
+ return new ScFormulaCell( pDestDoc, rDestPos, &aArr );
+}
+
+
+// rColumn = Quelle
+// nRow1, nRow2 = Zielposition
+
+void ScColumn::CopyFromClip(SCROW nRow1, SCROW nRow2, long nDy,
+ USHORT nInsFlag, BOOL bAsLink, BOOL bSkipAttrForEmpty,
+ ScColumn& rColumn)
+{
+ if ((nInsFlag & IDF_ATTRIB) != 0)
+ {
+ if ( bSkipAttrForEmpty )
+ {
+ // copy only attributes for non-empty cells
+ // (notes are not counted as non-empty here, to match the content behavior)
+
+ SCSIZE nStartIndex;
+ rColumn.Search( nRow1-nDy, nStartIndex );
+ while ( nStartIndex < rColumn.nCount && rColumn.pItems[nStartIndex].nRow <= nRow2-nDy )
+ {
+ SCSIZE nEndIndex = nStartIndex;
+ if ( rColumn.pItems[nStartIndex].pCell->GetCellType() != CELLTYPE_NOTE )
+ {
+ SCROW nStartRow = rColumn.pItems[nStartIndex].nRow;
+ SCROW nEndRow = nStartRow;
+
+ // find consecutive non-empty cells
+
+ while ( nEndRow < nRow2-nDy &&
+ nEndIndex+1 < rColumn.nCount &&
+ rColumn.pItems[nEndIndex+1].nRow == nEndRow+1 &&
+ rColumn.pItems[nEndIndex+1].pCell->GetCellType() != CELLTYPE_NOTE )
+ {
+ ++nEndIndex;
+ ++nEndRow;
+ }
+
+ rColumn.pAttrArray->CopyAreaSafe( nStartRow+nDy, nEndRow+nDy, nDy, *pAttrArray );
+ }
+ nStartIndex = nEndIndex + 1;
+ }
+ }
+ else
+ rColumn.pAttrArray->CopyAreaSafe( nRow1, nRow2, nDy, *pAttrArray );
+ }
+ if ((nInsFlag & IDF_CONTENTS) == 0)
+ return;
+
+ if ( bAsLink && nInsFlag == IDF_ALL )
+ {
+ // bei "alles" werden auch leere Zellen referenziert
+ //! IDF_ALL muss immer mehr Flags enthalten, als bei "Inhalte Einfuegen"
+ //! einzeln ausgewaehlt werden koennen!
+
+ Resize( nCount + static_cast<SCSIZE>(nRow2-nRow1+1) );
+
+ ScAddress aDestPos( nCol, 0, nTab ); // Row wird angepasst
+
+ // Referenz erzeugen (Quell-Position)
+ ScSingleRefData aRef;
+ aRef.nCol = rColumn.nCol;
+ // nRow wird angepasst
+ aRef.nTab = rColumn.nTab;
+ aRef.InitFlags(); // -> alles absolut
+ aRef.SetFlag3D(TRUE);
+
+ for (SCROW nDestRow = nRow1; nDestRow <= nRow2; nDestRow++)
+ {
+ aRef.nRow = nDestRow - nDy; // Quell-Zeile
+ aDestPos.SetRow( nDestRow );
+
+ aRef.CalcRelFromAbs( aDestPos );
+ ScTokenArray aArr;
+ aArr.AddSingleReference( aRef );
+ Insert( nDestRow, new ScFormulaCell( pDocument, aDestPos, &aArr ) );
+ }
+
+ return;
+ }
+
+ SCSIZE nColCount = rColumn.nCount;
+
+ // ignore IDF_FORMULA - "all contents but no formulas" results in the same number of cells
+ if ((nInsFlag & ( IDF_CONTENTS & ~IDF_FORMULA )) == ( IDF_CONTENTS & ~IDF_FORMULA ) && nRow2-nRow1 >= 64)
+ {
+ //! Always do the Resize from the outside, where the number of repetitions is known
+ //! (then it can be removed here)
+
+ SCSIZE nNew = nCount + nColCount;
+ if ( nLimit < nNew )
+ Resize( nNew );
+ }
+
+ BOOL bAtEnd = FALSE;
+ for (SCSIZE i = 0; i < nColCount && !bAtEnd; i++)
+ {
+ SCsROW nDestRow = rColumn.pItems[i].nRow + nDy;
+ if ( nDestRow > (SCsROW) nRow2 )
+ bAtEnd = TRUE;
+ else if ( nDestRow >= (SCsROW) nRow1 )
+ {
+ // rows at the beginning may be skipped if filtered rows are left out,
+ // nDestRow may be negative then
+
+ ScAddress aDestPos( nCol, (SCROW)nDestRow, nTab );
+ ScBaseCell* pNew = bAsLink ?
+ rColumn.CreateRefCell( pDocument, aDestPos, i, nInsFlag ) :
+ rColumn.CloneCell( i, nInsFlag, *pDocument, aDestPos );
+
+ if (pNew)
+ Insert((SCROW)nDestRow, pNew);
+ }
+ }
+}
+
+
+namespace {
+
+/** Helper for ScColumn::CloneCell - decides whether to clone a value cell depending on clone flags and number format. */
+bool lclCanCloneValue( ScDocument& rDoc, const ScColumn& rCol, SCROW nRow, bool bCloneValue, bool bCloneDateTime )
+{
+ // values and dates, or nothing to be cloned -> not needed to check number format
+ if( bCloneValue == bCloneDateTime )
+ return bCloneValue;
+
+ // check number format of value cell
+ ULONG nNumIndex = (ULONG)((SfxUInt32Item*)rCol.GetAttr( nRow, ATTR_VALUE_FORMAT ))->GetValue();
+ short nTyp = rDoc.GetFormatTable()->GetType( nNumIndex );
+ bool bIsDateTime = (nTyp == NUMBERFORMAT_DATE) || (nTyp == NUMBERFORMAT_TIME) || (nTyp == NUMBERFORMAT_DATETIME);
+ return bIsDateTime ? bCloneDateTime : bCloneValue;
+}
+
+} // namespace
+
+
+ScBaseCell* ScColumn::CloneCell(SCSIZE nIndex, USHORT nFlags, ScDocument& rDestDoc, const ScAddress& rDestPos)
+{
+ bool bCloneValue = (nFlags & IDF_VALUE) != 0;
+ bool bCloneDateTime = (nFlags & IDF_DATETIME) != 0;
+ bool bCloneString = (nFlags & IDF_STRING) != 0;
+ bool bCloneFormula = (nFlags & IDF_FORMULA) != 0;
+ bool bCloneNote = (nFlags & IDF_NOTE) != 0;
+
+ ScBaseCell* pNew = 0;
+ ScBaseCell& rSource = *pItems[nIndex].pCell;
+ switch (rSource.GetCellType())
+ {
+ case CELLTYPE_NOTE:
+ // note will be cloned below
+ break;
+
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ // note will be cloned below
+ if (bCloneString)
+ pNew = rSource.CloneWithoutNote( rDestDoc, rDestPos );
+ break;
+
+ case CELLTYPE_VALUE:
+ // note will be cloned below
+ if (lclCanCloneValue( *pDocument, *this, pItems[nIndex].nRow, bCloneValue, bCloneDateTime ))
+ pNew = rSource.CloneWithoutNote( rDestDoc, rDestPos );
+ break;
+
+ case CELLTYPE_FORMULA:
+ if (bCloneFormula)
+ {
+ // note will be cloned below
+ pNew = rSource.CloneWithoutNote( rDestDoc, rDestPos );
+ }
+ else if ( (bCloneValue || bCloneDateTime || bCloneString) && !rDestDoc.IsUndo() )
+ {
+ // #48491# ins Undo-Dokument immer nur die Original-Zelle kopieren,
+ // aus Formeln keine Value/String-Zellen erzeugen
+ ScFormulaCell& rForm = (ScFormulaCell&)rSource;
+ USHORT nErr = rForm.GetErrCode();
+ if ( nErr )
+ {
+ // error codes are cloned with values
+ if (bCloneValue)
+ {
+ ScFormulaCell* pErrCell = new ScFormulaCell( &rDestDoc, rDestPos );
+ pErrCell->SetErrCode( nErr );
+ pNew = pErrCell;
+ }
+ }
+ else if (rForm.IsValue())
+ {
+ if (lclCanCloneValue( *pDocument, *this, pItems[nIndex].nRow, bCloneValue, bCloneDateTime ))
+ {
+ double nVal = rForm.GetValue();
+ pNew = new ScValueCell(nVal);
+ }
+ }
+ else if (bCloneString)
+ {
+ String aString;
+ rForm.GetString( aString );
+ // #33224# do not clone empty string
+ if (aString.Len() > 0)
+ pNew = new ScStringCell( aString );
+ }
+ }
+ break;
+
+ default: DBG_ERRORFILE( "ScColumn::CloneCell - unknown cell type" );
+ }
+
+ // clone the cell note
+ if (bCloneNote)
+ {
+ if (ScPostIt* pNote = rSource.GetNote())
+ {
+ bool bCloneCaption = (nFlags & IDF_NOCAPTIONS) == 0;
+ // #i52342# if caption is cloned, the note must be constructed with the destination document
+ ScPostIt* pNewNote = ScNoteUtil::CloneNote( rDestDoc, rDestPos, *pNote, bCloneCaption );
+ if (!pNew)
+ pNew = new ScNoteCell( pNewNote );
+ else
+ pNew->TakeNote( pNewNote );
+ }
+ }
+
+ return pNew;
+}
+
+
+void ScColumn::MixMarked( const ScMarkData& rMark, USHORT nFunction,
+ BOOL bSkipEmpty, ScColumn& rSrcCol )
+{
+ SCROW nRow1, nRow2;
+
+ if (rMark.IsMultiMarked())
+ {
+ ScMarkArrayIter aIter( rMark.GetArray()+nCol );
+ while (aIter.Next( nRow1, nRow2 ))
+ MixData( nRow1, nRow2, nFunction, bSkipEmpty, rSrcCol );
+ }
+}
+
+
+// Ergebnis in rVal1
+
+BOOL lcl_DoFunction( double& rVal1, double nVal2, USHORT nFunction )
+{
+ BOOL bOk = FALSE;
+ switch (nFunction)
+ {
+ case PASTE_ADD:
+ bOk = SubTotal::SafePlus( rVal1, nVal2 );
+ break;
+ case PASTE_SUB:
+ nVal2 = -nVal2; //! geht das immer ohne Fehler?
+ bOk = SubTotal::SafePlus( rVal1, nVal2 );
+ break;
+ case PASTE_MUL:
+ bOk = SubTotal::SafeMult( rVal1, nVal2 );
+ break;
+ case PASTE_DIV:
+ bOk = SubTotal::SafeDiv( rVal1, nVal2 );
+ break;
+ }
+ return bOk;
+}
+
+
+void lcl_AddCode( ScTokenArray& rArr, ScFormulaCell* pCell )
+{
+ rArr.AddOpCode(ocOpen);
+
+ ScTokenArray* pCode = pCell->GetCode();
+ if (pCode)
+ {
+ const formula::FormulaToken* pToken = pCode->First();
+ while (pToken)
+ {
+ rArr.AddToken( *pToken );
+ pToken = pCode->Next();
+ }
+ }
+
+ rArr.AddOpCode(ocClose);
+}
+
+
+void ScColumn::MixData( SCROW nRow1, SCROW nRow2,
+ USHORT nFunction, BOOL bSkipEmpty,
+ ScColumn& rSrcCol )
+{
+ SCSIZE nSrcCount = rSrcCol.nCount;
+
+ SCSIZE nIndex;
+ Search( nRow1, nIndex );
+
+// SCSIZE nSrcIndex = 0;
+ SCSIZE nSrcIndex;
+ rSrcCol.Search( nRow1, nSrcIndex ); //! Testen, ob Daten ganz vorne
+
+ SCROW nNextThis = MAXROW+1;
+ if ( nIndex < nCount )
+ nNextThis = pItems[nIndex].nRow;
+ SCROW nNextSrc = MAXROW+1;
+ if ( nSrcIndex < nSrcCount )
+ nNextSrc = rSrcCol.pItems[nSrcIndex].nRow;
+
+ while ( nNextThis <= nRow2 || nNextSrc <= nRow2 )
+ {
+ SCROW nRow = Min( nNextThis, nNextSrc );
+
+ ScBaseCell* pSrc = NULL;
+ ScBaseCell* pDest = NULL;
+ ScBaseCell* pNew = NULL;
+ BOOL bDelete = FALSE;
+
+ if ( nSrcIndex < nSrcCount && nNextSrc == nRow )
+ pSrc = rSrcCol.pItems[nSrcIndex].pCell;
+
+ if ( nIndex < nCount && nNextThis == nRow )
+ pDest = pItems[nIndex].pCell;
+
+ DBG_ASSERT( pSrc || pDest, "Nanu ?" );
+
+ CellType eSrcType = pSrc ? pSrc->GetCellType() : CELLTYPE_NONE;
+ CellType eDestType = pDest ? pDest->GetCellType() : CELLTYPE_NONE;
+
+ BOOL bSrcEmpty = ( eSrcType == CELLTYPE_NONE || eSrcType == CELLTYPE_NOTE );
+ BOOL bDestEmpty = ( eDestType == CELLTYPE_NONE || eDestType == CELLTYPE_NOTE );
+
+ if ( bSkipEmpty && bDestEmpty ) // Originalzelle wiederherstellen
+ {
+ if ( pSrc ) // war da eine Zelle?
+ {
+ pNew = pSrc->CloneWithoutNote( *pDocument );
+ }
+ }
+ else if ( nFunction ) // wirklich Rechenfunktion angegeben
+ {
+ double nVal1;
+ double nVal2;
+ if ( eSrcType == CELLTYPE_VALUE )
+ nVal1 = ((ScValueCell*)pSrc)->GetValue();
+ else
+ nVal1 = 0.0;
+ if ( eDestType == CELLTYPE_VALUE )
+ nVal2 = ((ScValueCell*)pDest)->GetValue();
+ else
+ nVal2 = 0.0;
+
+ // leere Zellen werden als Werte behandelt
+
+ BOOL bSrcVal = ( bSrcEmpty || eSrcType == CELLTYPE_VALUE );
+ BOOL bDestVal = ( bDestEmpty || eDestType == CELLTYPE_VALUE );
+
+ BOOL bSrcText = ( eSrcType == CELLTYPE_STRING ||
+ eSrcType == CELLTYPE_EDIT );
+ BOOL bDestText = ( eDestType == CELLTYPE_STRING ||
+ eDestType == CELLTYPE_EDIT );
+
+ // sonst bleibt nur Formel...
+
+ if ( bSrcEmpty && bDestEmpty )
+ {
+ // beide leer -> nix
+ }
+ else if ( bSrcVal && bDestVal )
+ {
+ // neuen Wert eintragen, oder Fehler bei Ueberlauf
+
+ BOOL bOk = lcl_DoFunction( nVal1, nVal2, nFunction );
+
+ if (bOk)
+ pNew = new ScValueCell( nVal1 );
+ else
+ {
+ ScFormulaCell* pFC = new ScFormulaCell( pDocument,
+ ScAddress( nCol, nRow, nTab ) );
+ pFC->SetErrCode( errNoValue );
+ //! oder NOVALUE, dann auch in consoli,
+ //! sonst in Interpreter::GetCellValue die Abfrage auf errNoValue raus
+ //! (dann geht Stringzelle+Wertzelle nicht mehr)
+ pNew = pFC;
+ }
+ }
+ else if ( bSrcText || bDestText )
+ {
+ // mit Texten wird nicht gerechnet - immer "alte" Zelle, also pSrc
+
+ if (pSrc)
+ pNew = pSrc->CloneWithoutNote( *pDocument );
+ else if (pDest)
+ bDelete = TRUE;
+ }
+ else
+ {
+ // Kombination aus Wert und mindestens einer Formel -> Formel erzeugen
+
+ ScTokenArray aArr;
+
+ // erste Zelle
+ if ( eSrcType == CELLTYPE_FORMULA )
+ lcl_AddCode( aArr, (ScFormulaCell*)pSrc );
+ else
+ aArr.AddDouble( nVal1 );
+
+ // Operator
+ OpCode eOp = ocAdd;
+ switch ( nFunction )
+ {
+ case PASTE_ADD: eOp = ocAdd; break;
+ case PASTE_SUB: eOp = ocSub; break;
+ case PASTE_MUL: eOp = ocMul; break;
+ case PASTE_DIV: eOp = ocDiv; break;
+ }
+ aArr.AddOpCode(eOp); // Funktion
+
+ // zweite Zelle
+ if ( eDestType == CELLTYPE_FORMULA )
+ lcl_AddCode( aArr, (ScFormulaCell*)pDest );
+ else
+ aArr.AddDouble( nVal2 );
+
+ pNew = new ScFormulaCell( pDocument, ScAddress( nCol, nRow, nTab ), &aArr );
+ }
+ }
+
+
+ if ( pNew || bDelete ) // neues Ergebnis ?
+ {
+ if (pDest && !pNew) // alte Zelle da ?
+ {
+ if ( pDest->GetBroadcaster() )
+ pNew = new ScNoteCell; // Broadcaster uebernehmen
+ else
+ Delete(nRow); // -> loeschen
+ }
+ if (pNew)
+ Insert(nRow, pNew); // neue einfuegen
+
+ Search( nRow, nIndex ); // alles kann sich verschoben haben
+ if (pNew)
+ nNextThis = nRow; // nIndex zeigt jetzt genau auf nRow
+ else
+ nNextThis = ( nIndex < nCount ) ? pItems[nIndex].nRow : MAXROW+1;
+ }
+
+ if ( nNextThis == nRow )
+ {
+ ++nIndex;
+ nNextThis = ( nIndex < nCount ) ? pItems[nIndex].nRow : MAXROW+1;
+ }
+ if ( nNextSrc == nRow )
+ {
+ ++nSrcIndex;
+ nNextSrc = ( nSrcIndex < nSrcCount ) ?
+ rSrcCol.pItems[nSrcIndex].nRow :
+ MAXROW+1;
+ }
+ }
+}
+
+
+ScAttrIterator* ScColumn::CreateAttrIterator( SCROW nStartRow, SCROW nEndRow ) const
+{
+ return new ScAttrIterator( pAttrArray, nStartRow, nEndRow );
+}
+
+
+void ScColumn::StartAllListeners()
+{
+ if (pItems)
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ SCROW nRow = pItems[i].nRow;
+ ((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener eingefuegt?
+ }
+ }
+}
+
+
+void ScColumn::StartNeededListeners()
+{
+ if (pItems)
+ {
+ for (SCSIZE i = 0; i < nCount; i++)
+ {
+ ScBaseCell* pCell = pItems[i].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
+ if (pFCell->NeedsListening())
+ {
+ SCROW nRow = pItems[i].nRow;
+ pFCell->StartListeningTo( pDocument );
+ if ( nRow != pItems[i].nRow )
+ Search( nRow, i ); // Listener eingefuegt?
+ }
+ }
+ }
+ }
+}
+
+
+void ScColumn::BroadcastInArea( SCROW nRow1, SCROW nRow2 )
+{
+ if ( pItems )
+ {
+ SCROW nRow;
+ SCSIZE nIndex;
+ Search( nRow1, nIndex );
+ while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->SetDirty();
+ else
+ pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED,
+ ScAddress( nCol, nRow, nTab ), pCell ) );
+ nIndex++;
+ }
+ }
+}
+
+
+void ScColumn::StartListeningInArea( SCROW nRow1, SCROW nRow2 )
+{
+ if ( pItems )
+ {
+ SCROW nRow;
+ SCSIZE nIndex;
+ Search( nRow1, nIndex );
+ while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRow2 )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->StartListeningTo( pDocument );
+ if ( nRow != pItems[nIndex].nRow )
+ Search( nRow, nIndex ); // durch Listening eingefuegt
+ nIndex++;
+ }
+ }
+}
+
+
+// TRUE = Zahlformat gesetzt
+BOOL ScColumn::SetString( SCROW nRow, SCTAB nTabP, const String& rString,
+ formula::FormulaGrammar::AddressConvention eConv )
+{
+ BOOL bNumFmtSet = FALSE;
+ if (VALIDROW(nRow))
+ {
+ ScBaseCell* pNewCell = NULL;
+ BOOL bIsLoading = FALSE;
+ if (rString.Len() > 0)
+ {
+ double nVal;
+ sal_uInt32 nIndex, nOldIndex = 0;
+ sal_Unicode cFirstChar;
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+ SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
+ if ( pDocSh )
+ bIsLoading = pDocSh->IsLoading();
+ // IsLoading bei ConvertFrom Import
+ if ( !bIsLoading )
+ {
+ nIndex = nOldIndex = GetNumberFormat( nRow );
+ if ( rString.Len() > 1
+ && pFormatter->GetType(nIndex) != NUMBERFORMAT_TEXT )
+ cFirstChar = rString.GetChar(0);
+ else
+ cFirstChar = 0; // Text
+ }
+ else
+ { // waehrend ConvertFrom Import gibt es keine gesetzten Formate
+ cFirstChar = rString.GetChar(0);
+ }
+
+ if ( cFirstChar == '=' )
+ {
+ if ( rString.Len() == 1 ) // = Text
+ pNewCell = new ScStringCell( rString );
+ else // =Formel
+ pNewCell = new ScFormulaCell( pDocument,
+ ScAddress( nCol, nRow, nTabP ), rString,
+ formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_DEFAULT,
+ eConv), MM_NONE );
+ }
+ else if ( cFirstChar == '\'') // 'Text
+ pNewCell = new ScStringCell( rString.Copy(1) );
+ else
+ {
+ BOOL bIsText = FALSE;
+ if ( bIsLoading )
+ {
+ if ( pItems && nCount )
+ {
+ String aStr;
+ SCSIZE i = nCount;
+ SCSIZE nStop = (i >= 3 ? i - 3 : 0);
+ // die letzten Zellen vergleichen, ob gleicher String
+ // und IsNumberFormat eingespart werden kann
+ do
+ {
+ i--;
+ ScBaseCell* pCell = pItems[i].pCell;
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_STRING :
+ ((ScStringCell*)pCell)->GetString( aStr );
+ if ( rString == aStr )
+ bIsText = TRUE;
+ break;
+ case CELLTYPE_NOTE : // durch =Formel referenziert
+ break;
+ default:
+ if ( i == nCount - 1 )
+ i = 0;
+ // wahrscheinlich ganze Spalte kein String
+ }
+ } while ( i && i > nStop && !bIsText );
+ }
+ // nIndex fuer IsNumberFormat vorbelegen
+ if ( !bIsText )
+ nIndex = nOldIndex = pFormatter->GetStandardIndex();
+ }
+ if ( !bIsText &&
+ pFormatter->IsNumberFormat(rString, nIndex, nVal) )
+ { // Zahl
+ pNewCell = new ScValueCell( nVal );
+ if ( nIndex != nOldIndex)
+ {
+ // #i22345# New behavior: Apply the detected number format only if
+ // the old one was the default number, date, time or boolean format.
+ // Exception: If the new format is boolean, always apply it.
+
+ BOOL bOverwrite = FALSE;
+ const SvNumberformat* pOldFormat = pFormatter->GetEntry( nOldIndex );
+ if ( pOldFormat )
+ {
+ short nOldType = pOldFormat->GetType() & ~NUMBERFORMAT_DEFINED;
+ if ( nOldType == NUMBERFORMAT_NUMBER || nOldType == NUMBERFORMAT_DATE ||
+ nOldType == NUMBERFORMAT_TIME || nOldType == NUMBERFORMAT_LOGICAL )
+ {
+ if ( nOldIndex == pFormatter->GetStandardFormat(
+ nOldType, pOldFormat->GetLanguage() ) )
+ {
+ bOverwrite = TRUE; // default of these types can be overwritten
+ }
+ }
+ }
+ if ( !bOverwrite && pFormatter->GetType( nIndex ) == NUMBERFORMAT_LOGICAL )
+ {
+ bOverwrite = TRUE; // overwrite anything if boolean was detected
+ }
+
+ if ( bOverwrite )
+ {
+ ApplyAttr( nRow, SfxUInt32Item( ATTR_VALUE_FORMAT,
+ (UINT32) nIndex) );
+ bNumFmtSet = TRUE;
+ }
+ }
+ }
+ else // Text
+ pNewCell = new ScStringCell( rString );
+ }
+ }
+
+ if ( bIsLoading && (!nCount || nRow > pItems[nCount-1].nRow) )
+ { // Search einsparen und ohne Umweg ueber Insert, Listener aufbauen
+ // und Broadcast kommt eh erst nach dem Laden
+ if ( pNewCell )
+ Append( nRow, pNewCell );
+ }
+ else
+ {
+ SCSIZE i;
+ if (Search(nRow, i))
+ {
+ ScBaseCell* pOldCell = pItems[i].pCell;
+ ScPostIt* pNote = pOldCell->ReleaseNote();
+ SvtBroadcaster* pBC = pOldCell->ReleaseBroadcaster();
+ if (pNewCell || pNote || pBC)
+ {
+ if (pNewCell)
+ pNewCell->TakeNote( pNote );
+ else
+ pNewCell = new ScNoteCell( pNote );
+ if (pBC)
+ {
+ pNewCell->TakeBroadcaster(pBC);
+ pLastFormulaTreeTop = 0; // Err527 Workaround
+ }
+
+ if ( pOldCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ pOldCell->EndListeningTo( pDocument );
+ // falls in EndListening NoteCell in gleicher Col zerstoert
+ if ( i >= nCount || pItems[i].nRow != nRow )
+ Search(nRow, i);
+ }
+ pOldCell->Delete();
+ pItems[i].pCell = pNewCell; // ersetzen
+ if ( pNewCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ pNewCell->StartListeningTo( pDocument );
+ ((ScFormulaCell*)pNewCell)->SetDirty();
+ }
+ else
+ pDocument->Broadcast( ScHint( SC_HINT_DATACHANGED,
+ ScAddress( nCol, nRow, nTabP ), pNewCell ) );
+ }
+ else
+ {
+ DeleteAtIndex(i); // loeschen und Broadcast
+ }
+ }
+ else if (pNewCell)
+ {
+ Insert(nRow, pNewCell); // neu eintragen und Broadcast
+ }
+ }
+
+ // hier keine Formate mehr fuer Formeln setzen!
+ // (werden bei der Ausgabe abgefragt)
+
+ }
+ return bNumFmtSet;
+}
+
+
+void ScColumn::GetFilterEntries(SCROW nStartRow, SCROW nEndRow, TypedScStrCollection& rStrings)
+{
+ SvNumberFormatter* pFormatter = pDocument->GetFormatTable();
+ String aString;
+ SCROW nRow = 0;
+ SCSIZE nIndex;
+
+ Search( nStartRow, nIndex );
+
+ while ( (nIndex < nCount) ? ((nRow=pItems[nIndex].nRow) <= nEndRow) : FALSE )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ TypedStrData* pData;
+ ULONG nFormat = GetNumberFormat( nRow );
+
+ ScCellFormat::GetInputString( pCell, nFormat, aString, *pFormatter );
+
+ if ( pDocument->HasStringData( nCol, nRow, nTab ) )
+ pData = new TypedStrData( aString );
+ else
+ {
+ double nValue;
+
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE:
+ nValue = ((ScValueCell*)pCell)->GetValue();
+ break;
+
+ case CELLTYPE_FORMULA:
+ nValue = ((ScFormulaCell*)pCell)->GetValue();
+ break;
+
+ default:
+ nValue = 0.0;
+ }
+
+ pData = new TypedStrData( aString, nValue, SC_STRTYPE_VALUE );
+ }
+#if 0 // DR
+ ScPostIt aCellNote( ScPostIt::UNINITIALIZED );
+ // Hide visible notes during Filtering.
+ if(pCell->GetNote(aCellNote) && aCellNote.IsCaptionShown())
+ {
+ ScDetectiveFunc( pDocument, nTab ).HideComment( nCol, nRow );
+ aCellNote.SetShown( false );
+ pCell->SetNote(aCellNote);
+ }
+#endif
+
+ if ( !rStrings.Insert( pData ) )
+ delete pData; // doppelt
+
+ ++nIndex;
+ }
+}
+
+//
+// GetDataEntries - Strings aus zusammenhaengendem Bereich um nRow
+//
+
+// DATENT_MAX - max. Anzahl Eintrage in Liste fuer Auto-Eingabe
+// DATENT_SEARCH - max. Anzahl Zellen, die durchsucht werden - neu: nur Strings zaehlen
+#define DATENT_MAX 200
+#define DATENT_SEARCH 2000
+
+
+BOOL ScColumn::GetDataEntries(SCROW nStartRow, TypedScStrCollection& rStrings, BOOL bLimit)
+{
+ BOOL bFound = FALSE;
+ SCSIZE nThisIndex;
+ BOOL bThisUsed = Search( nStartRow, nThisIndex );
+ String aString;
+ USHORT nCells = 0;
+
+ // Die Beschraenkung auf angrenzende Zellen (ohne Luecken) ist nicht mehr gewollt
+ // (Featurekommission zur 5.1), stattdessen abwechselnd nach oben und unten suchen,
+ // damit naheliegende Zellen wenigstens zuerst gefunden werden.
+ //! Abstaende der Zeilennummern vergleichen? (Performance??)
+
+ SCSIZE nUpIndex = nThisIndex; // zeigt hinter die Zelle
+ SCSIZE nDownIndex = nThisIndex; // zeigt auf die Zelle
+ if (bThisUsed)
+ ++nDownIndex; // Startzelle ueberspringen
+
+ while ( nUpIndex || nDownIndex < nCount )
+ {
+ if ( nUpIndex ) // nach oben
+ {
+ ScBaseCell* pCell = pItems[nUpIndex-1].pCell;
+ CellType eType = pCell->GetCellType();
+ if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT) // nur Strings interessieren
+ {
+ if (eType == CELLTYPE_STRING)
+ ((ScStringCell*)pCell)->GetString(aString);
+ else
+ ((ScEditCell*)pCell)->GetString(aString);
+
+ TypedStrData* pData = new TypedStrData(aString);
+ if ( !rStrings.Insert( pData ) )
+ delete pData; // doppelt
+ else if ( bLimit && rStrings.GetCount() >= DATENT_MAX )
+ break; // Maximum erreicht
+ bFound = TRUE;
+
+ if ( bLimit )
+ if (++nCells >= DATENT_SEARCH)
+ break; // genug gesucht
+ }
+ --nUpIndex;
+ }
+
+ if ( nDownIndex < nCount ) // nach unten
+ {
+ ScBaseCell* pCell = pItems[nDownIndex].pCell;
+ CellType eType = pCell->GetCellType();
+ if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT) // nur Strings interessieren
+ {
+ if (eType == CELLTYPE_STRING)
+ ((ScStringCell*)pCell)->GetString(aString);
+ else
+ ((ScEditCell*)pCell)->GetString(aString);
+
+ TypedStrData* pData = new TypedStrData(aString);
+ if ( !rStrings.Insert( pData ) )
+ delete pData; // doppelt
+ else if ( bLimit && rStrings.GetCount() >= DATENT_MAX )
+ break; // Maximum erreicht
+ bFound = TRUE;
+
+ if ( bLimit )
+ if (++nCells >= DATENT_SEARCH)
+ break; // genug gesucht
+ }
+ ++nDownIndex;
+ }
+ }
+
+ return bFound;
+}
+
+#undef DATENT_MAX
+#undef DATENT_SEARCH
+
+
+void ScColumn::RemoveProtected( SCROW nStartRow, SCROW nEndRow )
+{
+ ScAttrIterator aAttrIter( pAttrArray, nStartRow, nEndRow );
+ SCROW nTop;
+ SCROW nBottom;
+ SCSIZE nIndex;
+ const ScPatternAttr* pPattern = aAttrIter.Next( nTop, nBottom );
+ while (pPattern)
+ {
+ const ScProtectionAttr* pAttr = (const ScProtectionAttr*)&pPattern->GetItem(ATTR_PROTECTION);
+ if ( pAttr->GetHideCell() )
+ DeleteArea( nTop, nBottom, IDF_CONTENTS );
+ else if ( pAttr->GetHideFormula() )
+ {
+ Search( nTop, nIndex );
+ while ( nIndex<nCount && pItems[nIndex].nRow<=nBottom )
+ {
+ if ( pItems[nIndex].pCell->GetCellType() == CELLTYPE_FORMULA )
+ {
+ ScFormulaCell* pFormula = (ScFormulaCell*)pItems[nIndex].pCell;
+ if (pFormula->IsValue())
+ {
+ double nVal = pFormula->GetValue();
+ pItems[nIndex].pCell = new ScValueCell( nVal );
+ }
+ else
+ {
+ String aString;
+ pFormula->GetString(aString);
+ pItems[nIndex].pCell = new ScStringCell( aString );
+ }
+ delete pFormula;
+ }
+ ++nIndex;
+ }
+ }
+
+ pPattern = aAttrIter.Next( nTop, nBottom );
+ }
+}
+
+
+void ScColumn::SetError( SCROW nRow, const USHORT nError)
+{
+ if (VALIDROW(nRow))
+ {
+ ScFormulaCell* pCell = new ScFormulaCell
+ ( pDocument, ScAddress( nCol, nRow, nTab ) );
+ pCell->SetErrCode( nError );
+ Insert( nRow, pCell );
+ }
+}
+
+
+void ScColumn::SetValue( SCROW nRow, const double& rVal)
+{
+ if (VALIDROW(nRow))
+ {
+ ScBaseCell* pCell = new ScValueCell(rVal);
+ Insert( nRow, pCell );
+ }
+}
+
+
+void ScColumn::GetString( SCROW nRow, String& rString ) const
+{
+ SCSIZE nIndex;
+ Color* pColor;
+ if (Search(nRow, nIndex))
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if (pCell->GetCellType() != CELLTYPE_NOTE)
+ {
+ ULONG nFormat = GetNumberFormat( nRow );
+ ScCellFormat::GetString( pCell, nFormat, rString, &pColor, *(pDocument->GetFormatTable()) );
+ }
+ else
+ rString.Erase();
+ }
+ else
+ rString.Erase();
+}
+
+
+void ScColumn::GetInputString( SCROW nRow, String& rString ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if (pCell->GetCellType() != CELLTYPE_NOTE)
+ {
+ ULONG nFormat = GetNumberFormat( nRow );
+ ScCellFormat::GetInputString( pCell, nFormat, rString, *(pDocument->GetFormatTable()) );
+ }
+ else
+ rString.Erase();
+ }
+ else
+ rString.Erase();
+}
+
+
+double ScColumn::GetValue( SCROW nRow ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ return ((ScValueCell*)pCell)->GetValue();
+// break;
+ case CELLTYPE_FORMULA:
+ {
+ if (((ScFormulaCell*)pCell)->IsValue())
+ return ((ScFormulaCell*)pCell)->GetValue();
+ else
+ return 0.0;
+ }
+// break;
+ default:
+ return 0.0;
+// break;
+ }
+ }
+ return 0.0;
+}
+
+
+void ScColumn::GetFormula( SCROW nRow, String& rFormula, BOOL ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ ((ScFormulaCell*)pCell)->GetFormula( rFormula );
+ else
+ rFormula.Erase();
+ }
+ else
+ rFormula.Erase();
+}
+
+
+CellType ScColumn::GetCellType( SCROW nRow ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ return pItems[nIndex].pCell->GetCellType();
+ return CELLTYPE_NONE;
+}
+
+
+USHORT ScColumn::GetErrCode( SCROW nRow ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ return ((ScFormulaCell*)pCell)->GetErrCode();
+ }
+ return 0;
+}
+
+
+BOOL ScColumn::HasStringData( SCROW nRow ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ return (pItems[nIndex].pCell)->HasStringData();
+ return FALSE;
+}
+
+
+BOOL ScColumn::HasValueData( SCROW nRow ) const
+{
+ SCSIZE nIndex;
+ if (Search(nRow, nIndex))
+ return (pItems[nIndex].pCell)->HasValueData();
+ return FALSE;
+}
+
+BOOL ScColumn::HasStringCells( SCROW nStartRow, SCROW nEndRow ) const
+{
+ // TRUE, wenn String- oder Editzellen im Bereich
+
+ if ( pItems )
+ {
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ while ( nIndex < nCount && pItems[nIndex].nRow <= nEndRow )
+ {
+ CellType eType = pItems[nIndex].pCell->GetCellType();
+ if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
+ return TRUE;
+ ++nIndex;
+ }
+ }
+ return FALSE;
+}
+
+
+ScPostIt* ScColumn::GetNote( SCROW nRow )
+{
+ SCSIZE nIndex;
+ return Search( nRow, nIndex ) ? pItems[ nIndex ].pCell->GetNote() : 0;
+}
+
+
+void ScColumn::TakeNote( SCROW nRow, ScPostIt* pNote )
+{
+ SCSIZE nIndex;
+ if( Search( nRow, nIndex ) )
+ pItems[ nIndex ].pCell->TakeNote( pNote );
+ else
+ Insert( nRow, new ScNoteCell( pNote ) );
+}
+
+
+ScPostIt* ScColumn::ReleaseNote( SCROW nRow )
+{
+ ScPostIt* pNote = 0;
+ SCSIZE nIndex;
+ if( Search( nRow, nIndex ) )
+ {
+ ScBaseCell* pCell = pItems[ nIndex ].pCell;
+ pNote = pCell->ReleaseNote();
+ if( (pCell->GetCellType() == CELLTYPE_NOTE) && !pCell->GetBroadcaster() )
+ DeleteAtIndex( nIndex );
+ }
+ return pNote;
+}
+
+
+void ScColumn::DeleteNote( SCROW nRow )
+{
+ delete ReleaseNote( nRow );
+}
+
+
+sal_Int32 ScColumn::GetMaxStringLen( SCROW nRowStart, SCROW nRowEnd, CharSet eCharSet ) const
+{
+ sal_Int32 nStringLen = 0;
+ if ( pItems )
+ {
+ String aString;
+ rtl::OString aOString;
+ bool bIsOctetTextEncoding = rtl_isOctetTextEncoding( eCharSet);
+ SvNumberFormatter* pNumFmt = pDocument->GetFormatTable();
+ SCSIZE nIndex;
+ SCROW nRow;
+ Search( nRowStart, nIndex );
+ while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRowEnd )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ if ( pCell->GetCellType() != CELLTYPE_NOTE )
+ {
+ Color* pColor;
+ ULONG nFormat = (ULONG) ((SfxUInt32Item*) GetAttr(
+ nRow, ATTR_VALUE_FORMAT ))->GetValue();
+ ScCellFormat::GetString( pCell, nFormat, aString, &pColor,
+ *pNumFmt );
+ sal_Int32 nLen;
+ if (bIsOctetTextEncoding)
+ {
+ rtl::OUString aOUString( aString);
+ if (!aOUString.convertToString( &aOString, eCharSet,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
+ {
+ // TODO: anything? this is used by the dBase export filter
+ // that throws an error anyway, but in case of another
+ // context we might want to indicate a conversion error
+ // early.
+ }
+ nLen = aOString.getLength();
+ }
+ else
+ nLen = aString.Len() * sizeof(sal_Unicode);
+ if ( nStringLen < nLen)
+ nStringLen = nLen;
+ }
+ nIndex++;
+ }
+ }
+ return nStringLen;
+}
+
+
+xub_StrLen ScColumn::GetMaxNumberStringLen( USHORT& nPrecision,
+ SCROW nRowStart, SCROW nRowEnd ) const
+{
+ xub_StrLen nStringLen = 0;
+ nPrecision = pDocument->GetDocOptions().GetStdPrecision();
+ if ( pItems )
+ {
+ String aString;
+ SvNumberFormatter* pNumFmt = pDocument->GetFormatTable();
+ SCSIZE nIndex;
+ SCROW nRow;
+ Search( nRowStart, nIndex );
+ while ( nIndex < nCount && (nRow = pItems[nIndex].nRow) <= nRowEnd )
+ {
+ ScBaseCell* pCell = pItems[nIndex].pCell;
+ CellType eType = pCell->GetCellType();
+ if ( eType == CELLTYPE_VALUE || (eType == CELLTYPE_FORMULA
+ && ((ScFormulaCell*)pCell)->IsValue()) )
+ {
+ ULONG nFormat = (ULONG) ((SfxUInt32Item*) GetAttr(
+ nRow, ATTR_VALUE_FORMAT ))->GetValue();
+ ScCellFormat::GetInputString( pCell, nFormat, aString, *pNumFmt );
+ xub_StrLen nLen = aString.Len();
+ if ( nLen )
+ {
+ if ( nFormat )
+ { // more decimals than standard?
+ USHORT nPrec = pNumFmt->GetFormatPrecision( nFormat );
+ if ( nPrec > nPrecision )
+ nPrecision = nPrec;
+ }
+ if ( nPrecision )
+ { // less than nPrecision in string => widen it
+ // more => shorten it
+ String aSep = pNumFmt->GetFormatDecimalSep( nFormat );
+ xub_StrLen nTmp = aString.Search( aSep );
+ if ( nTmp == STRING_NOTFOUND )
+ nLen += nPrecision + aSep.Len();
+ else
+ {
+ nTmp = aString.Len() - (nTmp + aSep.Len());
+ if ( nTmp != nPrecision )
+ nLen += nPrecision - nTmp;
+ // nPrecision > nTmp : nLen + Diff
+ // nPrecision < nTmp : nLen - Diff
+ }
+ }
+ if ( nStringLen < nLen )
+ nStringLen = nLen;
+ }
+ }
+ nIndex++;
+ }
+ }
+ return nStringLen;
+}
+
diff --git a/sc/source/core/data/compressedarray.cxx b/sc/source/core/data/compressedarray.cxx
new file mode 100644
index 000000000000..71edac0cd0c8
--- /dev/null
+++ b/sc/source/core/data/compressedarray.cxx
@@ -0,0 +1,909 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: compressedarray.cxx,v $
+ * $Revision: 1.10.32.1 $
+ *
+ * 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 "compressedarray.hxx"
+#include "address.hxx"
+
+#include <algorithm>
+
+template< typename A, typename D >
+ScCompressedArray<A,D>::ScCompressedArray( A nMaxAccessP, const D& rValue,
+ size_t nDeltaP )
+ : nCount(1)
+ , nLimit(1)
+ , nDelta( nDeltaP > 0 ? nDeltaP : 1)
+ , pData( new DataEntry[1])
+ , nMaxAccess( nMaxAccessP)
+{
+ pData[0].aValue = rValue;
+ pData[0].nEnd = nMaxAccess;
+}
+
+
+template< typename A, typename D >
+ScCompressedArray<A,D>::ScCompressedArray( A nMaxAccessP, const D* pDataArray,
+ size_t nDataCount )
+ : nCount(0)
+ , nLimit( nDataCount)
+ , nDelta( nScCompressedArrayDelta)
+ , pData( new DataEntry[nDataCount])
+ , nMaxAccess( nMaxAccessP)
+{
+ D aValue = pDataArray[0];
+ for (size_t j=0; j<nDataCount; ++j)
+ {
+ if (!(aValue == pDataArray[j]))
+ {
+ pData[nCount].aValue = aValue;
+ pData[nCount].nEnd = j-1;
+ ++nCount;
+ aValue = pDataArray[j];
+ }
+ }
+ pData[nCount].aValue = aValue;
+ pData[nCount].nEnd = nMaxAccess;
+ ++nCount;
+ Resize( nCount);
+}
+
+
+template< typename A, typename D >
+ScCompressedArray<A,D>::~ScCompressedArray()
+{
+ delete[] pData;
+}
+
+
+template< typename A, typename D >
+void ScCompressedArray<A,D>::Resize( size_t nNewLimit)
+{
+ if ((nCount <= nNewLimit && nNewLimit < nLimit) || nLimit < nNewLimit)
+ {
+ nLimit = nNewLimit;
+ DataEntry* pNewData = new DataEntry[nLimit];
+ memcpy( pNewData, pData, nCount*sizeof(DataEntry));
+ delete[] pData;
+ pData = pNewData;
+ }
+}
+
+
+template< typename A, typename D >
+size_t ScCompressedArray<A,D>::Search( A nAccess ) const
+{
+ if (nAccess == 0)
+ return 0;
+
+ long nLo = 0;
+ long nHi = static_cast<long>(nCount) - 1;
+ long nStart = 0;
+ long nEnd = 0;
+ long i = 0;
+ bool bFound = (nCount == 1);
+ while (!bFound && nLo <= nHi)
+ {
+ i = (nLo + nHi) / 2;
+ if (i > 0)
+ nStart = (long) pData[i - 1].nEnd;
+ else
+ nStart = -1;
+ nEnd = (long) pData[i].nEnd;
+ if (nEnd < (long) nAccess)
+ nLo = ++i;
+ else
+ if (nStart >= (long) nAccess)
+ nHi = --i;
+ else
+ bFound = true;
+ }
+ return (bFound ? static_cast<size_t>(i) : (nAccess < 0 ? 0 : nCount-1));
+}
+
+
+template< typename A, typename D >
+void ScCompressedArray<A,D>::SetValue( A nStart, A nEnd, const D& rValue )
+{
+ if (0 <= nStart && nStart <= nMaxAccess && 0 <= nEnd && nEnd <= nMaxAccess
+ && nStart <= nEnd)
+ {
+ if ((nStart == 0) && (nEnd == nMaxAccess))
+ Reset( rValue);
+ else
+ {
+ // Create a temporary copy in case we got a reference passed that
+ // points to a part of the array to be reallocated.
+ D aNewVal( rValue);
+ size_t nNeeded = nCount + 2;
+ if (nLimit < nNeeded)
+ {
+ nLimit += nDelta;
+ if (nLimit < nNeeded)
+ nLimit = nNeeded;
+ DataEntry* pNewData = new DataEntry[nLimit];
+ memcpy( pNewData, pData, nCount*sizeof(DataEntry));
+ delete[] pData;
+ pData = pNewData;
+ }
+
+ size_t ni; // number of leading entries
+ size_t nInsert; // insert position (nMaxAccess+1 := no insert)
+ bool bCombined = false;
+ bool bSplit = false;
+ if (nStart > 0)
+ {
+ // skip leading
+ ni = Search( nStart);
+
+ nInsert = nMaxAccess+1;
+ if (!(pData[ni].aValue == aNewVal))
+ {
+ if (ni == 0 || (pData[ni-1].nEnd < nStart - 1))
+ { // may be a split or a simple insert or just a shrink,
+ // row adjustment is done further down
+ if (pData[ni].nEnd > nEnd)
+ bSplit = true;
+ ni++;
+ nInsert = ni;
+ }
+ else if (ni > 0 && pData[ni-1].nEnd == nStart - 1)
+ nInsert = ni;
+ }
+ if (ni > 0 && pData[ni-1].aValue == aNewVal)
+ { // combine
+ pData[ni-1].nEnd = nEnd;
+ nInsert = nMaxAccess+1;
+ bCombined = true;
+ }
+ }
+ else
+ {
+ nInsert = 0;
+ ni = 0;
+ }
+
+ size_t nj = ni; // stop position of range to replace
+ while (nj < nCount && pData[nj].nEnd <= nEnd)
+ nj++;
+ if (!bSplit)
+ {
+ if (nj < nCount && pData[nj].aValue == aNewVal)
+ { // combine
+ if (ni > 0)
+ {
+ if (pData[ni-1].aValue == aNewVal)
+ { // adjacent entries
+ pData[ni-1].nEnd = pData[nj].nEnd;
+ nj++;
+ }
+ else if (ni == nInsert)
+ pData[ni-1].nEnd = nStart - 1; // shrink
+ }
+ nInsert = nMaxAccess+1;
+ bCombined = true;
+ }
+ else if (ni > 0 && ni == nInsert)
+ pData[ni-1].nEnd = nStart - 1; // shrink
+ }
+ if (ni < nj)
+ { // remove middle entries
+ if (!bCombined)
+ { // replace one entry
+ pData[ni].nEnd = nEnd;
+ pData[ni].aValue = aNewVal;
+ ni++;
+ nInsert = nMaxAccess+1;
+ }
+ if (ni < nj)
+ { // remove entries
+ memmove( pData + ni, pData + nj,
+ (nCount - nj) * sizeof(DataEntry));
+ nCount -= nj - ni;
+ }
+ }
+
+ if (nInsert < static_cast<size_t>(nMaxAccess+1))
+ { // insert or append new entry
+ if (nInsert <= nCount)
+ {
+ if (!bSplit)
+ memmove( pData + nInsert + 1, pData + nInsert,
+ (nCount - nInsert) * sizeof(DataEntry));
+ else
+ {
+ memmove( pData + nInsert + 2, pData + nInsert,
+ (nCount - nInsert) * sizeof(DataEntry));
+ pData[nInsert+1] = pData[nInsert-1];
+ nCount++;
+ }
+ }
+ if (nInsert)
+ pData[nInsert-1].nEnd = nStart - 1;
+ pData[nInsert].nEnd = nEnd;
+ pData[nInsert].aValue = aNewVal;
+ nCount++;
+ }
+ }
+ }
+}
+
+
+template< typename A, typename D >
+void ScCompressedArray<A,D>::CopyFrom( const ScCompressedArray<A,D>& rArray, A nStart,
+ A nEnd, long nSourceDy )
+{
+ size_t nIndex;
+ A nRegionEnd;
+ for (A j=nStart; j<=nEnd; ++j)
+ {
+ const D& rValue = (j==nStart ?
+ rArray.GetValue( j+nSourceDy, nIndex, nRegionEnd) :
+ rArray.GetNextValue( nIndex, nRegionEnd));
+ nRegionEnd -= nSourceDy;
+ if (nRegionEnd > nEnd)
+ nRegionEnd = nEnd;
+ SetValue( j, nRegionEnd, rValue);
+ j = nRegionEnd;
+ }
+}
+
+
+template< typename A, typename D >
+const D& ScCompressedArray<A,D>::Insert( A nStart, size_t nAccessCount )
+{
+ size_t nIndex = Search( nStart);
+ // No real insertion is needed, simply extend the one entry and adapt all
+ // following. In case nStart points to the start row of an entry, extend
+ // the previous entry (inserting before nStart).
+ if (nIndex > 0 && pData[nIndex-1].nEnd+1 == nStart)
+ --nIndex;
+ const D& rValue = pData[nIndex].aValue; // the value "copied"
+ do
+ {
+ pData[nIndex].nEnd += nAccessCount;
+ if (pData[nIndex].nEnd >= nMaxAccess)
+ {
+ pData[nIndex].nEnd = nMaxAccess;
+ nCount = nIndex + 1; // discard trailing entries
+ }
+ } while (++nIndex < nCount);
+ return rValue;
+}
+
+
+template< typename A, typename D >
+void ScCompressedArray<A,D>::Remove( A nStart, size_t nAccessCount )
+{
+ A nEnd = nStart + nAccessCount - 1;
+ size_t nIndex = Search( nStart);
+ // equalize/combine/remove all entries in between
+ if (nEnd > pData[nIndex].nEnd)
+ SetValue( nStart, nEnd, pData[nIndex].aValue);
+ // remove an exactly matching entry by shifting up all following by one
+ if ((nStart == 0 || (nIndex > 0 && nStart == pData[nIndex-1].nEnd+1)) &&
+ pData[nIndex].nEnd == nEnd && nIndex < nCount-1)
+ {
+ // In case removing an entry results in two adjacent entries with
+ // identical data, combine them into one. This is also necessary to
+ // make the algorithm used in SetValue() work correctly, it relies on
+ // the fact that consecutive values actually differ.
+ size_t nRemove;
+ if (nIndex > 0 && pData[nIndex-1].aValue == pData[nIndex+1].aValue)
+ {
+ nRemove = 2;
+ --nIndex;
+ }
+ else
+ nRemove = 1;
+ memmove( pData + nIndex, pData + nIndex + nRemove, (nCount - (nIndex +
+ nRemove)) * sizeof(DataEntry));
+ nCount -= nRemove;
+ }
+ // adjust end rows, nIndex still being valid
+ do
+ {
+ pData[nIndex].nEnd -= nAccessCount;
+ } while (++nIndex < nCount);
+ pData[nCount-1].nEnd = nMaxAccess;
+}
+
+
+template< typename A, typename D >
+A ScCompressedArray<A,D>::GetLastUnequalAccess( A nStart, const D& rCompare )
+{
+ A nEnd = ::std::numeric_limits<A>::max();
+ size_t nIndex = nCount-1;
+ while (1)
+ {
+ if (pData[nIndex].aValue != rCompare)
+ {
+ nEnd = pData[nIndex].nEnd;
+ break; // while
+ }
+ else
+ {
+ if (nIndex > 0)
+ {
+ --nIndex;
+ if (pData[nIndex].nEnd < nStart)
+ break; // while
+ }
+ else
+ break; // while
+ }
+ }
+ return nEnd;
+}
+
+
+// === ScSummableCompressedArray =============================================
+
+template< typename A, typename D >
+unsigned long ScSummableCompressedArray<A,D>::SumValues( A nStart, A nEnd ) const
+{
+ size_t nIndex = Search( nStart);
+ unsigned long nSum = SumValuesContinuation( nStart, nEnd, nIndex);
+ if (nEnd > this->nMaxAccess)
+ nSum += this->pData[this->nCount-1].aValue * (nEnd - this->nMaxAccess);
+ return nSum;
+}
+
+
+template< typename A, typename D >
+unsigned long ScSummableCompressedArray<A,D>::SumValuesContinuation(
+ A nStart, A nEnd, size_t& nIndex ) const
+{
+ unsigned long nSum = 0;
+ A nS = nStart;
+ while (nIndex < this->nCount && nS <= nEnd)
+ {
+ A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
+ // FIXME: test for overflow in a single region?
+ unsigned long nNew = (unsigned long) this->pData[nIndex].aValue * (nE - nS + 1);
+ nSum += nNew;
+ if (nSum < nNew)
+ return ::std::numeric_limits<unsigned long>::max();
+ nS = nE + 1;
+ if (nS <= nEnd)
+ ++nIndex;
+ }
+ return nSum;
+}
+
+
+template< typename A, typename D >
+unsigned long ScSummableCompressedArray<A,D>::SumScaledValuesContinuation(
+ A nStart, A nEnd, size_t& nIndex, double fScale ) const
+{
+ unsigned long nSum = 0;
+ A nS = nStart;
+ while (nIndex < this->nCount && nS <= nEnd)
+ {
+ A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
+ unsigned long nScaledVal = (unsigned long) (this->pData[nIndex].aValue * fScale);
+ // FIXME: test for overflow in a single region?
+ unsigned long nNew = nScaledVal * (nE - nS + 1);
+ nSum += nNew;
+ if (nSum < nNew)
+ return ::std::numeric_limits<unsigned long>::max();
+ nS = nE + 1;
+ if (nS <= nEnd)
+ ++nIndex;
+ }
+ return nSum;
+}
+
+
+// === ScBitMaskCompressedArray ==============================================
+
+template< typename A, typename D >
+void ScBitMaskCompressedArray<A,D>::AndValue( A nStart, A nEnd,
+ const D& rValueToAnd )
+{
+ if (nStart > nEnd)
+ return;
+
+ size_t nIndex = Search( nStart);
+ do
+ {
+ if ((this->pData[nIndex].aValue & rValueToAnd) != this->pData[nIndex].aValue)
+ {
+ A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
+ A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
+ SetValue( nS, nE, this->pData[nIndex].aValue & rValueToAnd);
+ if (nE >= nEnd)
+ break; // while
+ nIndex = Search( nE + 1);
+ }
+ else if (this->pData[nIndex].nEnd >= nEnd)
+ break; // while
+ else
+ ++nIndex;
+ } while (nIndex < this->nCount);
+}
+
+
+template< typename A, typename D >
+void ScBitMaskCompressedArray<A,D>::OrValue( A nStart, A nEnd,
+ const D& rValueToOr )
+{
+ if (nStart > nEnd)
+ return;
+
+ size_t nIndex = Search( nStart);
+ do
+ {
+ if ((this->pData[nIndex].aValue | rValueToOr) != this->pData[nIndex].aValue)
+ {
+ A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
+ A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
+ SetValue( nS, nE, this->pData[nIndex].aValue | rValueToOr);
+ if (nE >= nEnd)
+ break; // while
+ nIndex = Search( nE + 1);
+ }
+ else if (this->pData[nIndex].nEnd >= nEnd)
+ break; // while
+ else
+ ++nIndex;
+ } while (nIndex < this->nCount);
+}
+
+
+template< typename A, typename D >
+void ScBitMaskCompressedArray<A,D>::CopyFromAnded(
+ const ScBitMaskCompressedArray<A,D>& rArray, A nStart, A nEnd,
+ const D& rValueToAnd, long nSourceDy )
+{
+ size_t nIndex;
+ A nRegionEnd;
+ for (A j=nStart; j<=nEnd; ++j)
+ {
+ const D& rValue = (j==nStart ?
+ rArray.GetValue( j+nSourceDy, nIndex, nRegionEnd) :
+ rArray.GetNextValue( nIndex, nRegionEnd));
+ nRegionEnd -= nSourceDy;
+ if (nRegionEnd > nEnd)
+ nRegionEnd = nEnd;
+ SetValue( j, nRegionEnd, rValue & rValueToAnd);
+ j = nRegionEnd;
+ }
+}
+
+
+template< typename A, typename D >
+void ScBitMaskCompressedArray<A,D>::CopyFromOred(
+ const ScBitMaskCompressedArray<A,D>& rArray, A nStart, A nEnd,
+ const D& rValueToOr, long nSourceDy )
+{
+ size_t nIndex;
+ A nRegionEnd;
+ for (A j=nStart; j<=nEnd; ++j)
+ {
+ const D& rValue = (j==nStart ?
+ rArray.GetValue( j+nSourceDy, nIndex, nRegionEnd) :
+ rArray.GetNextValue( nIndex, nRegionEnd));
+ nRegionEnd -= nSourceDy;
+ if (nRegionEnd > nEnd)
+ nRegionEnd = nEnd;
+ SetValue( j, nRegionEnd, rValue | rValueToOr);
+ j = nRegionEnd;
+ }
+}
+
+
+template< typename A, typename D >
+A ScBitMaskCompressedArray<A,D>::GetBitStateStart( A nEnd,
+ const D& rBitMask, const D& rMaskedCompare ) const
+{
+ A nStart = ::std::numeric_limits<A>::max();
+ size_t nIndex = Search( nEnd);
+ while ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
+ {
+ if (nIndex > 0)
+ {
+ --nIndex;
+ nStart = this->pData[nIndex].nEnd + 1;
+ }
+ else
+ {
+ nStart = 0;
+ break; // while
+ }
+ }
+ return nStart;
+}
+
+
+template< typename A, typename D >
+A ScBitMaskCompressedArray<A,D>::GetBitStateEnd( A nStart,
+ const D& rBitMask, const D& rMaskedCompare ) const
+{
+ A nEnd = ::std::numeric_limits<A>::max();
+ size_t nIndex = Search( nStart);
+ while (nIndex < this->nCount && (this->pData[nIndex].aValue & rBitMask) ==
+ rMaskedCompare)
+ {
+ nEnd = this->pData[nIndex].nEnd;
+ ++nIndex;
+ }
+ return nEnd;
+}
+
+
+template< typename A, typename D >
+A ScBitMaskCompressedArray<A,D>::GetFirstForCondition( A nStart, A nEnd,
+ const D& rBitMask, const D& rMaskedCompare ) const
+{
+ size_t nIndex = Search( nStart);
+ do
+ {
+ if ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
+ {
+ A nFound = nIndex > 0 ? this->pData[nIndex-1].nEnd + 1 : 0;
+ return ::std::max( nFound, nStart);
+ }
+ if (this->pData[nIndex].nEnd >= nEnd)
+ break; // while
+ ++nIndex;
+ } while (nIndex < this->nCount);
+ return ::std::numeric_limits<A>::max();
+}
+
+
+template< typename A, typename D >
+A ScBitMaskCompressedArray<A,D>::GetLastForCondition( A nStart, A nEnd,
+ const D& rBitMask, const D& rMaskedCompare ) const
+{
+ size_t nIndex = Search( nEnd);
+ while (1)
+ {
+ if ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
+ return ::std::min( this->pData[nIndex].nEnd, nEnd);
+
+ if (nIndex > 0)
+ {
+ --nIndex;
+ if (this->pData[nIndex].nEnd < nStart)
+ break; // while
+ }
+ else
+ break; // while
+ }
+ return ::std::numeric_limits<A>::max();
+}
+
+
+template< typename A, typename D >
+A ScBitMaskCompressedArray<A,D>::CountForCondition( A nStart, A nEnd,
+ const D& rBitMask, const D& rMaskedCompare ) const
+{
+ A nRet = 0;
+ size_t nIndex = Search( nStart);
+ do
+ {
+ if ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
+ {
+ A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
+ A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
+ nRet += nE - nS + 1;
+ }
+ if (this->pData[nIndex].nEnd >= nEnd)
+ break; // while
+ ++nIndex;
+ } while (nIndex < this->nCount);
+ return nRet;
+}
+
+
+template< typename A, typename D >
+size_t ScBitMaskCompressedArray<A,D>::FillArrayForCondition( A nStart, A nEnd,
+ const D& rBitMask, const D& rMaskedCompare,
+ A * pArray, size_t nArraySize ) const
+{
+ size_t nUsed = 0;
+ size_t nIndex = Search( nStart);
+ while (nIndex < this->nCount && nUsed < nArraySize)
+ {
+ if ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
+ {
+ A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
+ A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
+ while (nS <= nE && nUsed < nArraySize)
+ pArray[nUsed++] = nS++;
+ }
+ if (this->pData[nIndex].nEnd >= nEnd)
+ break; // while
+ ++nIndex;
+ }
+ return nUsed;
+}
+
+
+template< typename A, typename D >
+bool ScBitMaskCompressedArray<A,D>::HasCondition( A nStart, A nEnd,
+ const D& rBitMask, const D& rMaskedCompare ) const
+{
+ size_t nIndex = Search( nStart);
+ do
+ {
+ if ((this->pData[nIndex].aValue & rBitMask) == rMaskedCompare)
+ return true;
+ if (this->pData[nIndex].nEnd >= nEnd)
+ break; // while
+ ++nIndex;
+ } while (nIndex < this->nCount);
+ return false;
+}
+
+
+template< typename A, typename D >
+A ScBitMaskCompressedArray<A,D>::CountForAnyBitCondition( A nStart, A nEnd,
+ const D& rBitMask ) const
+{
+ A nRet = 0;
+ size_t nIndex = Search( nStart);
+ do
+ {
+ if ((this->pData[nIndex].aValue & rBitMask) != 0)
+ {
+ A nS = ::std::max( (nIndex>0 ? this->pData[nIndex-1].nEnd+1 : 0), nStart);
+ A nE = ::std::min( this->pData[nIndex].nEnd, nEnd);
+ nRet += nE - nS + 1;
+ }
+ if (this->pData[nIndex].nEnd >= nEnd)
+ break; // while
+ ++nIndex;
+ } while (nIndex < this->nCount);
+ return nRet;
+}
+
+
+template< typename A, typename D >
+A ScBitMaskCompressedArray<A,D>::GetLastAnyBitAccess( A nStart,
+ const D& rBitMask ) const
+{
+ A nEnd = ::std::numeric_limits<A>::max();
+ size_t nIndex = this->nCount-1;
+ while (1)
+ {
+ if ((this->pData[nIndex].aValue & rBitMask) != 0)
+ {
+ nEnd = this->pData[nIndex].nEnd;
+ break; // while
+ }
+ else
+ {
+ if (nIndex > 0)
+ {
+ --nIndex;
+ if (this->pData[nIndex].nEnd < nStart)
+ break; // while
+ }
+ else
+ break; // while
+ }
+ }
+ return nEnd;
+}
+
+
+template< typename A, typename D >
+template< typename S >
+unsigned long ScBitMaskCompressedArray<A,D>::SumCoupledArrayForCondition(
+ A nStart, A nEnd, const D& rBitMask, const D& rMaskedCompare,
+ const ScSummableCompressedArray<A,S>& rArray ) const
+{
+ unsigned long nSum = 0;
+ A nS = nStart;
+ size_t nIndex1 = Search( nStart);
+ size_t nIndex2 = rArray.Search( nStart);
+ do
+ {
+ if ((this->pData[nIndex1].aValue & rBitMask) == rMaskedCompare)
+ {
+ while (nIndex2 < rArray.GetEntryCount() &&
+ rArray.GetDataEntry(nIndex2).nEnd < nS)
+ ++nIndex2;
+ unsigned long nNew = rArray.SumValuesContinuation( nS,
+ ::std::min( this->pData[nIndex1].nEnd, nEnd), nIndex2);
+ nSum += nNew;
+ if (nSum < nNew)
+ return ::std::numeric_limits<unsigned long>::max();
+ }
+ nS = this->pData[nIndex1].nEnd + 1;
+ ++nIndex1;
+ } while (nIndex1 < this->nCount && nS <= nEnd);
+ if (nEnd > this->nMaxAccess &&
+ (this->pData[this->GetEntryCount()-1].aValue & rBitMask) == rMaskedCompare)
+ nSum += rArray.GetDataEntry(rArray.GetEntryCount()-1).aValue * (nEnd -
+ this->nMaxAccess);
+ return nSum;
+}
+
+
+template< typename A, typename D >
+template< typename S >
+unsigned long ScBitMaskCompressedArray<A,D>::SumScaledCoupledArrayForCondition(
+ A nStart, A nEnd, const D& rBitMask, const D& rMaskedCompare,
+ const ScSummableCompressedArray<A,S>& rArray, double fScale ) const
+{
+ unsigned long nSum = 0;
+ A nS = nStart;
+ size_t nIndex1 = Search( nStart);
+ size_t nIndex2 = rArray.Search( nStart);
+ do
+ {
+ if ((this->pData[nIndex1].aValue & rBitMask) == rMaskedCompare)
+ {
+ while (nIndex2 < rArray.GetEntryCount() &&
+ rArray.GetDataEntry(nIndex2).nEnd < nS)
+ ++nIndex2;
+ unsigned long nNew = rArray.SumScaledValuesContinuation( nS,
+ ::std::min( this->pData[nIndex1].nEnd, nEnd), nIndex2, fScale);
+ nSum += nNew;
+ if (nSum < nNew)
+ return ::std::numeric_limits<unsigned long>::max();
+ }
+ nS = this->pData[nIndex1].nEnd + 1;
+ ++nIndex1;
+ } while (nIndex1 < this->nCount && nS <= nEnd);
+ if (nEnd > this->nMaxAccess &&
+ (this->pData[this->GetEntryCount()-1].aValue & rBitMask) == rMaskedCompare)
+ nSum += (unsigned long)
+ (rArray.GetDataEntry(rArray.GetEntryCount()-1).aValue * fScale) *
+ (nEnd - this->nMaxAccess);
+ return nSum;
+}
+
+
+// === ScCompressedArrayIterator =============================================
+
+template< typename A, typename D >
+template< typename X >
+void ScCompressedArrayIterator<A,D>::Follow(
+ const ScCompressedArrayIterator<A,X>& rIter )
+{
+ nCurrent = rIter.GetPos();
+ if (GetRangeStart() <= nCurrent && nCurrent <= GetRangeEnd())
+ ; // nothing
+ else if (nCurrent > GetRangeEnd())
+ {
+ A nPos = nCurrent; // nCurrent gets changed in NextRange()
+ bool bAdv;
+ do
+ {
+ bAdv = NextRange();
+ } while (bAdv && GetRangeEnd() < nPos);
+ nCurrent = nPos;
+ }
+ else
+ nIndex = rArray.Search( nCurrent);
+}
+
+
+// === ScCoupledCompressedArrayIterator ======================================
+
+template< typename A, typename D, typename S >
+ScCoupledCompressedArrayIterator<A,D,S>::ScCoupledCompressedArrayIterator(
+ const ScBitMaskCompressedArray<A,D> & rArray1, A nStart, A nEnd,
+ const D& rBitMaskP, const D& rMaskedCompareP,
+ const ScCompressedArray<A,S> & rArray2 )
+ : aIter1( rArray1, nStart, nEnd )
+ , aIter2( rArray2, nStart, nEnd )
+ , rBitMask( rBitMaskP )
+ , rMaskedCompare( rMaskedCompareP )
+{
+ InitLimits();
+}
+
+
+template< typename A, typename D, typename S >
+void ScCoupledCompressedArrayIterator<A,D,S>::InitLimits()
+{
+ bool bFound = true;
+ bool bMoved = false;
+ while (bFound && ((*aIter1 & rBitMask) != rMaskedCompare))
+ {
+ bFound = aIter1.NextRange();
+ bMoved = true;
+ }
+ if (bMoved && bFound)
+ aIter2.Follow( aIter1);
+}
+
+
+template< typename A, typename D, typename S >
+void ScCoupledCompressedArrayIterator<A,D,S>::NewLimits( A nStart, A nEnd )
+{
+ aIter1.NewLimits( nStart, nEnd);
+ aIter2.NewLimits( nStart, nEnd);
+ InitLimits();
+}
+
+
+template< typename A, typename D, typename S >
+bool ScCoupledCompressedArrayIterator<A,D,S>::NextRange()
+{
+ bool bAdv;
+ if (aIter1.GetRangeEnd() <= aIter2.GetRangeEnd())
+ {
+ // Advance bit mask array until condition is met, coupled array
+ // follows.
+ do
+ {
+ bAdv = aIter1.NextRange();
+ } while (bAdv && ((*aIter1 & rBitMask) != rMaskedCompare));
+ if (bAdv)
+ aIter2.Follow( aIter1);
+ }
+ else
+ {
+ // Make coupled array catch up with bit mask array.
+ do
+ {
+ bAdv = aIter2.NextRange();
+ } while (bAdv && aIter2.GetRangeEnd() < aIter1.GetRangeStart());
+ if (bAdv)
+ aIter1.Follow( aIter2); // synchronize aIter1.nCurrent
+ }
+ return operator bool();
+}
+
+
+template< typename A, typename D, typename S >
+void ScCoupledCompressedArrayIterator<A,D,S>::Resync( A nPos )
+{
+ aIter1.Resync( nPos);
+ aIter2.Resync( nPos);
+ InitLimits();
+}
+
+
+// === Force instantiation of specializations ================================
+
+template class ScCompressedArray< SCROW, USHORT>; // heights, base class
+template class ScSummableCompressedArray< SCROW, USHORT>; // heights
+template class ScCompressedArray< SCROW, BYTE>; // flags, base class
+template class ScBitMaskCompressedArray< SCROW, BYTE>; // flags
+template unsigned long ScBitMaskCompressedArray< SCROW,
+ BYTE>::SumCoupledArrayForCondition( SCROW, SCROW, const BYTE&, const BYTE&,
+ const ScSummableCompressedArray< SCROW, USHORT>&) const;
+template unsigned long ScBitMaskCompressedArray< SCROW,
+ BYTE>::SumScaledCoupledArrayForCondition( SCROW, SCROW, const BYTE&,
+ const BYTE&, const ScSummableCompressedArray< SCROW, USHORT>&,
+ double) const;
+template void ScCompressedArrayIterator< SCROW, USHORT>::Follow(
+ const ScCompressedArrayIterator< SCROW, BYTE>&);
+template class ScCoupledCompressedArrayIterator< SCROW, BYTE, USHORT>;
+
+// === EOF ===================================================================
diff --git a/sc/source/core/data/conditio.cxx b/sc/source/core/data/conditio.cxx
new file mode 100644
index 000000000000..b6b063002957
--- /dev/null
+++ b/sc/source/core/data/conditio.cxx
@@ -0,0 +1,1585 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: conditio.cxx,v $
+ * $Revision: 1.25.30.5 $
+ *
+ * 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 <sfx2/objsh.hxx>
+#include <svtools/itemset.hxx>
+#include <svtools/zforlist.hxx>
+#include <rtl/math.hxx>
+#include <unotools/collatorwrapper.hxx>
+
+#include "conditio.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "hints.hxx"
+#include "compiler.hxx"
+#include "rechead.hxx"
+#include "rangelst.hxx"
+#include "stlpool.hxx"
+#include "rangenam.hxx"
+
+using namespace formula;
+//------------------------------------------------------------------------
+
+SV_IMPL_OP_PTRARR_SORT( ScConditionalFormats_Impl, ScConditionalFormatPtr );
+
+//------------------------------------------------------------------------
+
+BOOL lcl_HasRelRef( ScDocument* pDoc, ScTokenArray* pFormula, USHORT nRecursion = 0 )
+{
+ if (pFormula)
+ {
+ pFormula->Reset();
+ FormulaToken* t;
+ for( t = pFormula->Next(); t; t = pFormula->Next() )
+ {
+ switch( t->GetType() )
+ {
+ case svDoubleRef:
+ {
+ ScSingleRefData& rRef2 = static_cast<ScToken*>(t)->GetDoubleRef().Ref2;
+ if ( rRef2.IsColRel() || rRef2.IsRowRel() || rRef2.IsTabRel() )
+ return TRUE;
+ }
+ // fall through
+
+ case svSingleRef:
+ {
+ ScSingleRefData& rRef1 = static_cast<ScToken*>(t)->GetSingleRef();
+ if ( rRef1.IsColRel() || rRef1.IsRowRel() || rRef1.IsTabRel() )
+ return TRUE;
+ }
+ break;
+
+ case svIndex:
+ {
+ if( t->GetOpCode() == ocName ) // DB areas always absolute
+ if( ScRangeData* pRangeData = pDoc->GetRangeName()->FindIndex( t->GetIndex() ) )
+ if( (nRecursion < 42) && lcl_HasRelRef( pDoc, pRangeData->GetCode(), nRecursion + 1 ) )
+ return TRUE;
+ }
+ break;
+
+ // #i34474# function result dependent on cell position
+ case svByte:
+ {
+ switch( t->GetOpCode() )
+ {
+ case ocRow: // ROW() returns own row index
+ case ocColumn: // COLUMN() returns own column index
+ case ocTable: // SHEET() returns own sheet index
+ case ocCell: // CELL() may return own cell address
+ return TRUE;
+// break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+ScConditionEntry::ScConditionEntry( const ScConditionEntry& r ) :
+ eOp(r.eOp),
+ nOptions(r.nOptions),
+ nVal1(r.nVal1),
+ nVal2(r.nVal2),
+ aStrVal1(r.aStrVal1),
+ aStrVal2(r.aStrVal2),
+ eTempGrammar(r.eTempGrammar),
+ bIsStr1(r.bIsStr1),
+ bIsStr2(r.bIsStr2),
+ pFormula1(NULL),
+ pFormula2(NULL),
+ aSrcPos(r.aSrcPos),
+ aSrcString(r.aSrcString),
+ pFCell1(NULL),
+ pFCell2(NULL),
+ pDoc(r.pDoc),
+ bRelRef1(r.bRelRef1),
+ bRelRef2(r.bRelRef2),
+ bFirstRun(TRUE)
+{
+ // ScTokenArray copy ctor erzeugt flache Kopie
+
+ if (r.pFormula1)
+ pFormula1 = new ScTokenArray( *r.pFormula1 );
+ if (r.pFormula2)
+ pFormula2 = new ScTokenArray( *r.pFormula2 );
+
+ // Formelzellen werden erst bei IsValid angelegt
+}
+
+ScConditionEntry::ScConditionEntry( ScDocument* pDocument, const ScConditionEntry& r ) :
+ eOp(r.eOp),
+ nOptions(r.nOptions),
+ nVal1(r.nVal1),
+ nVal2(r.nVal2),
+ aStrVal1(r.aStrVal1),
+ aStrVal2(r.aStrVal2),
+ eTempGrammar(r.eTempGrammar),
+ bIsStr1(r.bIsStr1),
+ bIsStr2(r.bIsStr2),
+ pFormula1(NULL),
+ pFormula2(NULL),
+ aSrcPos(r.aSrcPos),
+ aSrcString(r.aSrcString),
+ pFCell1(NULL),
+ pFCell2(NULL),
+ pDoc(pDocument),
+ bRelRef1(r.bRelRef1),
+ bRelRef2(r.bRelRef2),
+ bFirstRun(TRUE)
+{
+ // echte Kopie der Formeln (fuer Ref-Undo)
+
+ if (r.pFormula1)
+ pFormula1 = r.pFormula1->Clone();
+ if (r.pFormula2)
+ pFormula2 = r.pFormula2->Clone();
+
+ // Formelzellen werden erst bei IsValid angelegt
+ //! im Clipboard nicht - dann vorher interpretieren !!!
+}
+
+ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
+ const String& rExpr1, const String& rExpr2,
+ ScDocument* pDocument, const ScAddress& rPos,
+ const FormulaGrammar::Grammar eGrammar ) :
+ eOp(eOper),
+ nOptions(0), // spaeter...
+ nVal1(0.0),
+ nVal2(0.0),
+ eTempGrammar(eGrammar),
+ bIsStr1(FALSE),
+ bIsStr2(FALSE),
+ pFormula1(NULL),
+ pFormula2(NULL),
+ aSrcPos(rPos),
+ pFCell1(NULL),
+ pFCell2(NULL),
+ pDoc(pDocument),
+ bRelRef1(FALSE),
+ bRelRef2(FALSE),
+ bFirstRun(TRUE)
+{
+ Compile( rExpr1, rExpr2, eGrammar, FALSE );
+
+ // Formelzellen werden erst bei IsValid angelegt
+}
+
+ScConditionEntry::ScConditionEntry( ScConditionMode eOper,
+ const ScTokenArray* pArr1, const ScTokenArray* pArr2,
+ ScDocument* pDocument, const ScAddress& rPos ) :
+ eOp(eOper),
+ nOptions(0), // spaeter...
+ nVal1(0.0),
+ nVal2(0.0),
+ eTempGrammar(FormulaGrammar::GRAM_DEFAULT),
+ bIsStr1(FALSE),
+ bIsStr2(FALSE),
+ pFormula1(NULL),
+ pFormula2(NULL),
+ aSrcPos(rPos),
+ pFCell1(NULL),
+ pFCell2(NULL),
+ pDoc(pDocument),
+ bRelRef1(FALSE),
+ bRelRef2(FALSE),
+ bFirstRun(TRUE)
+{
+ if ( pArr1 )
+ {
+ pFormula1 = new ScTokenArray( *pArr1 );
+ if ( pFormula1->GetLen() == 1 )
+ {
+ // einzelne (konstante Zahl) ?
+ FormulaToken* pToken = pFormula1->First();
+ if ( pToken->GetOpCode() == ocPush )
+ {
+ if ( pToken->GetType() == svDouble )
+ {
+ nVal1 = pToken->GetDouble();
+ DELETEZ(pFormula1); // nicht als Formel merken
+ }
+ else if ( pToken->GetType() == svString )
+ {
+ bIsStr1 = TRUE;
+ aStrVal1 = pToken->GetString();
+ DELETEZ(pFormula1); // nicht als Formel merken
+ }
+ }
+ }
+ bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 );
+ }
+ if ( pArr2 )
+ {
+ pFormula2 = new ScTokenArray( *pArr2 );
+ if ( pFormula2->GetLen() == 1 )
+ {
+ // einzelne (konstante Zahl) ?
+ FormulaToken* pToken = pFormula2->First();
+ if ( pToken->GetOpCode() == ocPush )
+ {
+ if ( pToken->GetType() == svDouble )
+ {
+ nVal2 = pToken->GetDouble();
+ DELETEZ(pFormula2); // nicht als Formel merken
+ }
+ else if ( pToken->GetType() == svString )
+ {
+ bIsStr2 = TRUE;
+ aStrVal2 = pToken->GetString();
+ DELETEZ(pFormula2); // nicht als Formel merken
+ }
+ }
+ }
+ bRelRef2 = lcl_HasRelRef( pDoc, pFormula2 );
+ }
+
+ // formula cells are created at IsValid
+}
+
+ScConditionEntry::~ScConditionEntry()
+{
+ delete pFCell1;
+ delete pFCell2;
+
+ delete pFormula1;
+ delete pFormula2;
+}
+
+void ScConditionEntry::Compile( const String& rExpr1, const String& rExpr2,
+ const FormulaGrammar::Grammar eGrammar, BOOL bTextToReal )
+{
+ if ( rExpr1.Len() || rExpr2.Len() )
+ {
+ ScCompiler aComp( pDoc, aSrcPos );
+ aComp.SetGrammar(eGrammar);
+
+ if ( rExpr1.Len() )
+ {
+ if ( pDoc->IsImportingXML() && !bTextToReal )
+ {
+ // temporary formula string as string tokens
+ //! merge with lcl_ScDocFunc_CreateTokenArrayXML
+ pFormula1 = new ScTokenArray;
+ pFormula1->AddString( rExpr1 );
+ // bRelRef1 is set when the formula is compiled again (CompileXML)
+ }
+ else
+ {
+ pFormula1 = aComp.CompileString( rExpr1 );
+ if ( pFormula1->GetLen() == 1 )
+ {
+ // einzelne (konstante Zahl) ?
+ FormulaToken* pToken = pFormula1->First();
+ if ( pToken->GetOpCode() == ocPush )
+ {
+ if ( pToken->GetType() == svDouble )
+ {
+ nVal1 = pToken->GetDouble();
+ DELETEZ(pFormula1); // nicht als Formel merken
+ }
+ else if ( pToken->GetType() == svString )
+ {
+ bIsStr1 = TRUE;
+ aStrVal1 = pToken->GetString();
+ DELETEZ(pFormula1); // nicht als Formel merken
+ }
+ }
+ }
+ bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 );
+ }
+ }
+
+ if ( rExpr2.Len() )
+ {
+ if ( pDoc->IsImportingXML() && !bTextToReal )
+ {
+ // temporary formula string as string tokens
+ //! merge with lcl_ScDocFunc_CreateTokenArrayXML
+ pFormula2 = new ScTokenArray;
+ pFormula2->AddString( rExpr2 );
+ // bRelRef2 is set when the formula is compiled again (CompileXML)
+ }
+ else
+ {
+ pFormula2 = aComp.CompileString( rExpr2 );
+ if ( pFormula2->GetLen() == 1 )
+ {
+ // einzelne (konstante Zahl) ?
+ FormulaToken* pToken = pFormula2->First();
+ if ( pToken->GetOpCode() == ocPush )
+ {
+ if ( pToken->GetType() == svDouble )
+ {
+ nVal2 = pToken->GetDouble();
+ DELETEZ(pFormula2); // nicht als Formel merken
+ }
+ else if ( pToken->GetType() == svString )
+ {
+ bIsStr2 = TRUE;
+ aStrVal2 = pToken->GetString();
+ DELETEZ(pFormula2); // nicht als Formel merken
+ }
+ }
+ }
+ bRelRef2 = lcl_HasRelRef( pDoc, pFormula2 );
+ }
+ }
+ }
+}
+
+void ScConditionEntry::MakeCells( const ScAddress& rPos ) // Formelzellen anlegen
+{
+ if ( !pDoc->IsClipOrUndo() ) // nie im Clipboard rechnen!
+ {
+ if ( pFormula1 && !pFCell1 && !bRelRef1 )
+ {
+ pFCell1 = new ScFormulaCell( pDoc, rPos, pFormula1 );
+ pFCell1->StartListeningTo( pDoc );
+ }
+
+ if ( pFormula2 && !pFCell2 && !bRelRef2 )
+ {
+ pFCell2 = new ScFormulaCell( pDoc, rPos, pFormula2 );
+ pFCell2->StartListeningTo( pDoc );
+ }
+ }
+}
+
+void ScConditionEntry::SetIgnoreBlank(BOOL bSet)
+{
+ // Das Bit SC_COND_NOBLANKS wird gesetzt, wenn Blanks nicht ignoriert werden
+ // (nur bei Gueltigkeit)
+
+ if (bSet)
+ nOptions &= ~SC_COND_NOBLANKS;
+ else
+ nOptions |= SC_COND_NOBLANKS;
+}
+
+void ScConditionEntry::CompileAll()
+{
+ // Formelzellen loeschen, dann wird beim naechsten IsValid neu kompiliert
+
+ DELETEZ(pFCell1);
+ DELETEZ(pFCell2);
+}
+
+void ScConditionEntry::CompileXML()
+{
+ // #b4974740# First parse the formula source position if it was stored as text
+
+ if ( aSrcString.Len() )
+ {
+ ScAddress aNew;
+ /* XML is always in OOo:A1 format, although R1C1 would be more amenable
+ * to compression */
+ if ( aNew.Parse( aSrcString, pDoc ) & SCA_VALID )
+ aSrcPos = aNew;
+ // if the position is invalid, there isn't much we can do at this time
+ aSrcString.Erase();
+ }
+
+ // Convert the text tokens that were created during XML import into real tokens.
+
+ Compile( GetExpression(aSrcPos, 0, 0, eTempGrammar),
+ GetExpression(aSrcPos, 1, 0, eTempGrammar),
+ eTempGrammar, TRUE );
+}
+
+void ScConditionEntry::SetSrcString( const String& rNew )
+{
+ // aSrcString is only evaluated in CompileXML
+ DBG_ASSERT( pDoc->IsImportingXML(), "SetSrcString is only valid for XML import" );
+
+ aSrcString = rNew;
+}
+
+void ScConditionEntry::SetFormula1( const ScTokenArray& rArray )
+{
+ DELETEZ( pFormula1 );
+ if( rArray.GetLen() > 0 )
+ {
+ pFormula1 = new ScTokenArray( rArray );
+ bRelRef1 = lcl_HasRelRef( pDoc, pFormula1 );
+ }
+}
+
+void ScConditionEntry::SetFormula2( const ScTokenArray& rArray )
+{
+ DELETEZ( pFormula2 );
+ if( rArray.GetLen() > 0 )
+ {
+ pFormula2 = new ScTokenArray( rArray );
+ bRelRef2 = lcl_HasRelRef( pDoc, pFormula2 );
+ }
+}
+
+void lcl_CondUpdateInsertTab( ScTokenArray& rCode, SCTAB nInsTab, SCTAB nPosTab, BOOL& rChanged )
+{
+ // Insert table: only update absolute table references.
+ // (Similar to ScCompiler::UpdateInsertTab with bIsName=TRUE, result is the same as for named ranges)
+ // For deleting, ScCompiler::UpdateDeleteTab is used because of the handling of invalid references.
+
+ rCode.Reset();
+ ScToken* p = static_cast<ScToken*>(rCode.GetNextReference());
+ while( p )
+ {
+ ScSingleRefData& rRef1 = p->GetSingleRef();
+ if ( !rRef1.IsTabRel() && nInsTab <= rRef1.nTab )
+ {
+ rRef1.nTab += 1;
+ rRef1.nRelTab = rRef1.nTab - nPosTab;
+ rChanged = TRUE;
+ }
+ if( p->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = p->GetDoubleRef().Ref2;
+ if ( !rRef2.IsTabRel() && nInsTab <= rRef2.nTab )
+ {
+ rRef2.nTab += 1;
+ rRef2.nRelTab = rRef2.nTab - nPosTab;
+ rChanged = TRUE;
+ }
+ }
+ p = static_cast<ScToken*>(rCode.GetNextReference());
+ }
+}
+
+void ScConditionEntry::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ BOOL bInsertTab = ( eUpdateRefMode == URM_INSDEL && nDz == 1 );
+ BOOL bDeleteTab = ( eUpdateRefMode == URM_INSDEL && nDz == -1 );
+
+ BOOL bChanged1 = FALSE;
+ BOOL bChanged2 = FALSE;
+
+ if (pFormula1)
+ {
+ if ( bInsertTab )
+ lcl_CondUpdateInsertTab( *pFormula1, rRange.aStart.Tab(), aSrcPos.Tab(), bChanged1 );
+ else
+ {
+ ScCompiler aComp( pDoc, aSrcPos, *pFormula1 );
+ aComp.SetGrammar(pDoc->GetGrammar());
+ if ( bDeleteTab )
+ aComp.UpdateDeleteTab( rRange.aStart.Tab(), FALSE, TRUE, bChanged1 );
+ else
+ aComp.UpdateNameReference( eUpdateRefMode, rRange, nDx, nDy, nDz, bChanged1 );
+ }
+
+ if (bChanged1)
+ DELETEZ(pFCell1); // is created again in IsValid
+ }
+ if (pFormula2)
+ {
+ if ( bInsertTab )
+ lcl_CondUpdateInsertTab( *pFormula2, rRange.aStart.Tab(), aSrcPos.Tab(), bChanged2 );
+ else
+ {
+ ScCompiler aComp( pDoc, aSrcPos, *pFormula2);
+ aComp.SetGrammar(pDoc->GetGrammar());
+ if ( bDeleteTab )
+ aComp.UpdateDeleteTab( rRange.aStart.Tab(), FALSE, TRUE, bChanged2 );
+ else
+ aComp.UpdateNameReference( eUpdateRefMode, rRange, nDx, nDy, nDz, bChanged2 );
+ }
+
+ if (bChanged2)
+ DELETEZ(pFCell2); // is created again in IsValid
+ }
+}
+
+void ScConditionEntry::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
+{
+ if (pFormula1)
+ {
+ ScCompiler aComp( pDoc, aSrcPos, *pFormula1);
+ aComp.SetGrammar(pDoc->GetGrammar());
+ aComp.UpdateMoveTab(nOldPos, nNewPos, TRUE );
+ DELETEZ(pFCell1);
+ }
+ if (pFormula2)
+ {
+ ScCompiler aComp( pDoc, aSrcPos, *pFormula2);
+ aComp.SetGrammar(pDoc->GetGrammar());
+ aComp.UpdateMoveTab(nOldPos, nNewPos, TRUE );
+ DELETEZ(pFCell2);
+ }
+}
+
+//! als Vergleichsoperator ans TokenArray ???
+
+BOOL lcl_IsEqual( const ScTokenArray* pArr1, const ScTokenArray* pArr2 )
+{
+ // verglichen wird nur das nicht-UPN Array
+
+ if ( pArr1 && pArr2 )
+ {
+ USHORT nLen = pArr1->GetLen();
+ if ( pArr2->GetLen() != nLen )
+ return FALSE;
+
+ FormulaToken** ppToken1 = pArr1->GetArray();
+ FormulaToken** ppToken2 = pArr2->GetArray();
+ for (USHORT i=0; i<nLen; i++)
+ {
+ if ( ppToken1[i] != ppToken2[i] &&
+ !(*ppToken1[i] == *ppToken2[i]) )
+ return FALSE; // Unterschied
+ }
+ return TRUE; // alle Eintraege gleich
+ }
+ else
+ return !pArr1 && !pArr2; // beide 0 -> gleich
+}
+
+int ScConditionEntry::operator== ( const ScConditionEntry& r ) const
+{
+ BOOL bEq = (eOp == r.eOp && nOptions == r.nOptions &&
+ lcl_IsEqual( pFormula1, r.pFormula1 ) &&
+ lcl_IsEqual( pFormula2, r.pFormula2 ));
+ if (bEq)
+ {
+ // for formulas, the reference positions must be compared, too
+ // (including aSrcString, for inserting the entries during XML import)
+ if ( ( pFormula1 || pFormula2 ) && ( aSrcPos != r.aSrcPos || aSrcString != r.aSrcString ) )
+ bEq = FALSE;
+
+ // wenn keine Formeln, Werte vergleichen
+ if ( !pFormula1 && ( nVal1 != r.nVal1 || aStrVal1 != r.aStrVal1 || bIsStr1 != r.bIsStr1 ) )
+ bEq = FALSE;
+ if ( !pFormula2 && ( nVal2 != r.nVal2 || aStrVal2 != r.aStrVal2 || bIsStr2 != r.bIsStr2 ) )
+ bEq = FALSE;
+ }
+
+ return bEq;
+}
+
+void ScConditionEntry::Interpret( const ScAddress& rPos )
+{
+ // Formelzellen anlegen
+ // dabei koennen neue Broadcaster (Note-Zellen) ins Dokument eingefuegt werden !!!!
+
+ if ( ( pFormula1 && !pFCell1 ) || ( pFormula2 && !pFCell2 ) )
+ MakeCells( rPos );
+
+ // Formeln auswerten
+
+ BOOL bDirty = FALSE; //! 1 und 2 getrennt ???
+
+ ScFormulaCell* pTemp1 = NULL;
+ ScFormulaCell* pEff1 = pFCell1;
+ if ( bRelRef1 )
+ {
+ pTemp1 = new ScFormulaCell( pDoc, rPos, pFormula1 ); // ohne Listening
+ pEff1 = pTemp1;
+ }
+ if ( pEff1 )
+ {
+ if (!pEff1->IsRunning()) // keine 522 erzeugen
+ {
+ //! Changed statt Dirty abfragen !!!
+ if (pEff1->GetDirty() && !bRelRef1)
+ bDirty = TRUE;
+ if (pEff1->IsValue())
+ {
+ bIsStr1 = FALSE;
+ nVal1 = pEff1->GetValue();
+ aStrVal1.Erase();
+ }
+ else
+ {
+ bIsStr1 = TRUE;
+ pEff1->GetString( aStrVal1 );
+ nVal1 = 0.0;
+ }
+ }
+ }
+ delete pTemp1;
+
+ ScFormulaCell* pTemp2 = NULL;
+ ScFormulaCell* pEff2 = pFCell2; //@ 1!=2
+ if ( bRelRef2 )
+ {
+ pTemp2 = new ScFormulaCell( pDoc, rPos, pFormula2 ); // ohne Listening
+ pEff2 = pTemp2;
+ }
+ if ( pEff2 )
+ {
+ if (!pEff2->IsRunning()) // keine 522 erzeugen
+ {
+ if (pEff2->GetDirty() && !bRelRef2)
+ bDirty = TRUE;
+ if (pEff2->IsValue())
+ {
+ bIsStr2 = FALSE;
+ nVal2 = pEff2->GetValue();
+ aStrVal2.Erase();
+ }
+ else
+ {
+ bIsStr2 = TRUE;
+ pEff2->GetString( aStrVal2 );
+ nVal2 = 0.0;
+ }
+ }
+ }
+ delete pTemp2;
+
+ // wenn IsRunning, bleiben die letzten Werte erhalten
+
+ if (bDirty && !bFirstRun)
+ {
+ // bei bedingten Formaten neu painten
+
+ DataChanged( NULL ); // alles
+ }
+
+ bFirstRun = FALSE;
+}
+
+BOOL ScConditionEntry::IsValid( double nArg ) const
+{
+ // Interpret muss schon gerufen sein
+
+ if ( bIsStr1 )
+ {
+ // wenn auf String getestet wird, bei Zahlen immer FALSE, ausser bei "ungleich"
+
+ return ( eOp == SC_COND_NOTEQUAL );
+ }
+
+ if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
+ if ( bIsStr2 )
+ return FALSE;
+
+ double nComp1 = nVal1; // Kopie, damit vertauscht werden kann
+ double nComp2 = nVal2;
+
+ if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
+ if ( nComp1 > nComp2 )
+ {
+ // richtige Reihenfolge fuer Wertebereich
+ double nTemp = nComp1; nComp1 = nComp2; nComp2 = nTemp;
+ }
+
+ // Alle Grenzfaelle muessen per ::rtl::math::approxEqual getestet werden!
+
+ BOOL bValid = FALSE;
+ switch (eOp)
+ {
+ case SC_COND_NONE:
+ break; // immer FALSE;
+ case SC_COND_EQUAL:
+ bValid = ::rtl::math::approxEqual( nArg, nComp1 );
+ break;
+ case SC_COND_NOTEQUAL:
+ bValid = !::rtl::math::approxEqual( nArg, nComp1 );
+ break;
+ case SC_COND_GREATER:
+ bValid = ( nArg > nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
+ break;
+ case SC_COND_EQGREATER:
+ bValid = ( nArg >= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
+ break;
+ case SC_COND_LESS:
+ bValid = ( nArg < nComp1 ) && !::rtl::math::approxEqual( nArg, nComp1 );
+ break;
+ case SC_COND_EQLESS:
+ bValid = ( nArg <= nComp1 ) || ::rtl::math::approxEqual( nArg, nComp1 );
+ break;
+ case SC_COND_BETWEEN:
+ bValid = ( nArg >= nComp1 && nArg <= nComp2 ) ||
+ ::rtl::math::approxEqual( nArg, nComp1 ) || ::rtl::math::approxEqual( nArg, nComp2 );
+ break;
+ case SC_COND_NOTBETWEEN:
+ bValid = ( nArg < nComp1 || nArg > nComp2 ) &&
+ !::rtl::math::approxEqual( nArg, nComp1 ) && !::rtl::math::approxEqual( nArg, nComp2 );
+ break;
+ case SC_COND_DIRECT:
+ bValid = !::rtl::math::approxEqual( nComp1, 0.0 );
+ break;
+ default:
+ DBG_ERROR("unbekannte Operation bei ScConditionEntry");
+ break;
+ }
+ return bValid;
+}
+
+BOOL ScConditionEntry::IsValidStr( const String& rArg ) const
+{
+ // Interpret muss schon gerufen sein
+
+ if ( eOp == SC_COND_DIRECT ) // Formel ist unabhaengig vom Inhalt
+ return !::rtl::math::approxEqual( nVal1, 0.0 );
+
+ // Wenn Bedingung Zahl enthaelt, immer FALSE, ausser bei "ungleich"
+
+ if ( !bIsStr1 )
+ return ( eOp == SC_COND_NOTEQUAL );
+ if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
+ if ( !bIsStr2 )
+ return FALSE;
+
+ String aUpVal1( aStrVal1 ); //! als Member? (dann auch in Interpret setzen)
+ String aUpVal2( aStrVal2 );
+
+ if ( eOp == SC_COND_BETWEEN || eOp == SC_COND_NOTBETWEEN )
+ if ( ScGlobal::pCollator->compareString( aUpVal1, aUpVal2 )
+ == COMPARE_GREATER )
+ {
+ // richtige Reihenfolge fuer Wertebereich
+ String aTemp( aUpVal1 ); aUpVal1 = aUpVal2; aUpVal2 = aTemp;
+ }
+
+ BOOL bValid;
+ switch ( eOp )
+ {
+ case SC_COND_EQUAL:
+ bValid = (ScGlobal::pCollator->compareString(
+ rArg, aUpVal1 ) == COMPARE_EQUAL);
+ break;
+ case SC_COND_NOTEQUAL:
+ bValid = (ScGlobal::pCollator->compareString(
+ rArg, aUpVal1 ) != COMPARE_EQUAL);
+ break;
+ default:
+ {
+ sal_Int32 nCompare = ScGlobal::pCollator->compareString(
+ rArg, aUpVal1 );
+ switch ( eOp )
+ {
+ case SC_COND_GREATER:
+ bValid = ( nCompare == COMPARE_GREATER );
+ break;
+ case SC_COND_EQGREATER:
+ bValid = ( nCompare == COMPARE_EQUAL || nCompare == COMPARE_GREATER );
+ break;
+ case SC_COND_LESS:
+ bValid = ( nCompare == COMPARE_LESS );
+ break;
+ case SC_COND_EQLESS:
+ bValid = ( nCompare == COMPARE_EQUAL || nCompare == COMPARE_LESS );
+ break;
+ case SC_COND_BETWEEN:
+ case SC_COND_NOTBETWEEN:
+ // Test auf NOTBETWEEN:
+ bValid = ( nCompare == COMPARE_LESS ||
+ ScGlobal::pCollator->compareString( rArg,
+ aUpVal2 ) == COMPARE_GREATER );
+ if ( eOp == SC_COND_BETWEEN )
+ bValid = !bValid;
+ break;
+ // SC_COND_DIRECT schon oben abgefragt
+ default:
+ DBG_ERROR("unbekannte Operation bei ScConditionEntry");
+ bValid = FALSE;
+ break;
+ }
+ }
+ }
+ return bValid;
+}
+
+BOOL ScConditionEntry::IsCellValid( ScBaseCell* pCell, const ScAddress& rPos ) const
+{
+ ((ScConditionEntry*)this)->Interpret(rPos); // Formeln auswerten
+
+ double nArg = 0.0;
+ String aArgStr;
+ BOOL bVal = TRUE;
+
+ if ( pCell )
+ {
+ CellType eType = pCell->GetCellType();
+ switch (eType)
+ {
+ case CELLTYPE_VALUE:
+ nArg = ((ScValueCell*)pCell)->GetValue();
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ bVal = pFCell->IsValue();
+ if (bVal)
+ nArg = pFCell->GetValue();
+ else
+ pFCell->GetString(aArgStr);
+ }
+ break;
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ bVal = FALSE;
+ if ( eType == CELLTYPE_STRING )
+ ((ScStringCell*)pCell)->GetString(aArgStr);
+ else
+ ((ScEditCell*)pCell)->GetString(aArgStr);
+ break;
+
+ default:
+ pCell = NULL; // Note-Zellen wie leere
+ break;
+ }
+ }
+
+ if (!pCell)
+ if (bIsStr1)
+ bVal = FALSE; // leere Zellen je nach Bedingung
+
+ if (bVal)
+ return IsValid( nArg );
+ else
+ return IsValidStr( aArgStr );
+}
+
+String ScConditionEntry::GetExpression( const ScAddress& rCursor, USHORT nIndex,
+ ULONG nNumFmt,
+ const FormulaGrammar::Grammar eGrammar ) const
+{
+ String aRet;
+
+ if ( FormulaGrammar::isEnglish( eGrammar) && nNumFmt == 0 )
+ nNumFmt = pDoc->GetFormatTable()->GetStandardIndex( LANGUAGE_ENGLISH_US );
+
+ if ( nIndex==0 )
+ {
+ if ( pFormula1 )
+ {
+ ScCompiler aComp(pDoc, rCursor, *pFormula1);
+ aComp.SetGrammar(eGrammar);
+ aComp.CreateStringFromTokenArray( aRet );
+ }
+ else if (bIsStr1)
+ {
+ aRet = '"';
+ aRet += aStrVal1;
+ aRet += '"';
+ }
+ else
+ pDoc->GetFormatTable()->GetInputLineString(nVal1, nNumFmt, aRet);
+ }
+ else if ( nIndex==1 )
+ {
+ if ( pFormula2 )
+ {
+ ScCompiler aComp(pDoc, rCursor, *pFormula2);
+ aComp.SetGrammar(eGrammar);
+ aComp.CreateStringFromTokenArray( aRet );
+ }
+ else if (bIsStr2)
+ {
+ aRet = '"';
+ aRet += aStrVal2;
+ aRet += '"';
+ }
+ else
+ pDoc->GetFormatTable()->GetInputLineString(nVal2, nNumFmt, aRet);
+ }
+ else
+ {
+ DBG_ERROR("GetExpression: falscher Index");
+ }
+
+ return aRet;
+}
+
+ScTokenArray* ScConditionEntry::CreateTokenArry( USHORT nIndex ) const
+{
+ ScTokenArray* pRet = NULL;
+ ScAddress aAddr;
+
+ if ( nIndex==0 )
+ {
+ if ( pFormula1 )
+ pRet = new ScTokenArray( *pFormula1 );
+ else
+ {
+ pRet = new ScTokenArray();
+ if (bIsStr1)
+ pRet->AddString( aStrVal1.GetBuffer() );
+ else
+ pRet->AddDouble( nVal1 );
+ }
+ }
+ else if ( nIndex==1 )
+ {
+ if ( pFormula2 )
+ pRet = new ScTokenArray( *pFormula2 );
+ else
+ {
+ pRet = new ScTokenArray();
+ if (bIsStr2)
+ pRet->AddString( aStrVal2.GetBuffer() );
+ else
+ pRet->AddDouble( nVal2 );
+ }
+ }
+ else
+ {
+ DBG_ERROR("GetExpression: falscher Index");
+ }
+
+ return pRet;
+}
+
+void ScConditionEntry::SourceChanged( const ScAddress& rChanged )
+{
+ for (USHORT nPass = 0; nPass < 2; nPass++)
+ {
+ ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
+ if (pFormula)
+ {
+ pFormula->Reset();
+ ScToken* t;
+ while ( ( t = static_cast<ScToken*>(pFormula->GetNextReference()) ) != NULL )
+ {
+ SingleDoubleRefProvider aProv( *t );
+ if ( aProv.Ref1.IsColRel() || aProv.Ref1.IsRowRel() || aProv.Ref1.IsTabRel() ||
+ aProv.Ref2.IsColRel() || aProv.Ref2.IsRowRel() || aProv.Ref2.IsTabRel() )
+ {
+ // absolut muss getroffen sein, relativ bestimmt Bereich
+
+ BOOL bHit = TRUE;
+ SCsCOL nCol1;
+ SCsROW nRow1;
+ SCsTAB nTab1;
+ SCsCOL nCol2;
+ SCsROW nRow2;
+ SCsTAB nTab2;
+
+ if ( aProv.Ref1.IsColRel() )
+ nCol2 = rChanged.Col() - aProv.Ref1.nRelCol;
+ else
+ {
+ bHit &= ( rChanged.Col() >= aProv.Ref1.nCol );
+ nCol2 = MAXCOL;
+ }
+ if ( aProv.Ref1.IsRowRel() )
+ nRow2 = rChanged.Row() - aProv.Ref1.nRelRow;
+ else
+ {
+ bHit &= ( rChanged.Row() >= aProv.Ref1.nRow );
+ nRow2 = MAXROW;
+ }
+ if ( aProv.Ref1.IsTabRel() )
+ nTab2 = rChanged.Tab() - aProv.Ref1.nRelTab;
+ else
+ {
+ bHit &= ( rChanged.Tab() >= aProv.Ref1.nTab );
+ nTab2 = MAXTAB;
+ }
+
+ if ( aProv.Ref2.IsColRel() )
+ nCol1 = rChanged.Col() - aProv.Ref2.nRelCol;
+ else
+ {
+ bHit &= ( rChanged.Col() <= aProv.Ref2.nCol );
+ nCol1 = 0;
+ }
+ if ( aProv.Ref2.IsRowRel() )
+ nRow1 = rChanged.Row() - aProv.Ref2.nRelRow;
+ else
+ {
+ bHit &= ( rChanged.Row() <= aProv.Ref2.nRow );
+ nRow1 = 0;
+ }
+ if ( aProv.Ref2.IsTabRel() )
+ nTab1 = rChanged.Tab() - aProv.Ref2.nRelTab;
+ else
+ {
+ bHit &= ( rChanged.Tab() <= aProv.Ref2.nTab );
+ nTab1 = 0;
+ }
+
+ if ( bHit )
+ {
+ //! begrenzen
+
+ ScRange aPaint( nCol1,nRow1,nTab1, nCol2,nRow2,nTab2 );
+
+ // kein Paint, wenn es nur die Zelle selber ist
+ if ( aPaint.aStart != rChanged || aPaint.aEnd != rChanged )
+ DataChanged( &aPaint );
+ }
+ }
+ }
+ }
+ }
+}
+
+ScAddress ScConditionEntry::GetValidSrcPos() const
+{
+ // return a position that's adjusted to allow textual representation of expressions if possible
+
+ SCTAB nMinTab = aSrcPos.Tab();
+ SCTAB nMaxTab = nMinTab;
+
+ for (USHORT nPass = 0; nPass < 2; nPass++)
+ {
+ ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
+ if (pFormula)
+ {
+ pFormula->Reset();
+ ScToken* t;
+ while ( ( t = static_cast<ScToken*>(pFormula->GetNextReference()) ) != NULL )
+ {
+ ScSingleRefData& rRef1 = t->GetSingleRef();
+ if ( rRef1.IsTabRel() && !rRef1.IsTabDeleted() )
+ {
+ if ( rRef1.nTab < nMinTab )
+ nMinTab = rRef1.nTab;
+ if ( rRef1.nTab > nMaxTab )
+ nMaxTab = rRef1.nTab;
+ }
+ if ( t->GetType() == svDoubleRef )
+ {
+ ScSingleRefData& rRef2 = t->GetDoubleRef().Ref2;
+ if ( rRef2.IsTabRel() && !rRef2.IsTabDeleted() )
+ {
+ if ( rRef2.nTab < nMinTab )
+ nMinTab = rRef2.nTab;
+ if ( rRef2.nTab > nMaxTab )
+ nMaxTab = rRef2.nTab;
+ }
+ }
+ }
+ }
+ }
+
+ ScAddress aValidPos = aSrcPos;
+ SCTAB nTabCount = pDoc->GetTableCount();
+ if ( nMaxTab >= nTabCount && nMinTab > 0 )
+ aValidPos.SetTab( aSrcPos.Tab() - nMinTab ); // so the lowest tab ref will be on 0
+
+ if ( aValidPos.Tab() >= nTabCount )
+ aValidPos.SetTab( nTabCount - 1 ); // ensure a valid position even if some references will be invalid
+
+ return aValidPos;
+}
+
+void ScConditionEntry::DataChanged( const ScRange* /* pModified */ ) const
+{
+ // nix
+}
+
+bool ScConditionEntry::MarkUsedExternalReferences() const
+{
+ bool bAllMarked = false;
+ for (USHORT nPass = 0; !bAllMarked && nPass < 2; nPass++)
+ {
+ ScTokenArray* pFormula = nPass ? pFormula2 : pFormula1;
+ if (pFormula)
+ bAllMarked = pDoc->MarkUsedExternalReferences( *pFormula);
+ }
+ return bAllMarked;
+}
+
+//------------------------------------------------------------------------
+
+ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
+ const String& rExpr1, const String& rExpr2,
+ ScDocument* pDocument, const ScAddress& rPos,
+ const String& rStyle,
+ const FormulaGrammar::Grammar eGrammar ) :
+ ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, eGrammar ),
+ aStyleName( rStyle ),
+ pParent( NULL )
+{
+}
+
+ScCondFormatEntry::ScCondFormatEntry( ScConditionMode eOper,
+ const ScTokenArray* pArr1, const ScTokenArray* pArr2,
+ ScDocument* pDocument, const ScAddress& rPos,
+ const String& rStyle ) :
+ ScConditionEntry( eOper, pArr1, pArr2, pDocument, rPos ),
+ aStyleName( rStyle ),
+ pParent( NULL )
+{
+}
+
+ScCondFormatEntry::ScCondFormatEntry( const ScCondFormatEntry& r ) :
+ ScConditionEntry( r ),
+ aStyleName( r.aStyleName ),
+ pParent( NULL )
+{
+}
+
+ScCondFormatEntry::ScCondFormatEntry( ScDocument* pDocument, const ScCondFormatEntry& r ) :
+ ScConditionEntry( pDocument, r ),
+ aStyleName( r.aStyleName ),
+ pParent( NULL )
+{
+}
+
+int ScCondFormatEntry::operator== ( const ScCondFormatEntry& r ) const
+{
+ return ScConditionEntry::operator==( r ) &&
+ aStyleName == r.aStyleName;
+
+ // Range wird nicht verglichen
+}
+
+ScCondFormatEntry::~ScCondFormatEntry()
+{
+}
+
+void ScCondFormatEntry::DataChanged( const ScRange* pModified ) const
+{
+ if ( pParent )
+ pParent->DoRepaint( pModified );
+}
+
+//------------------------------------------------------------------------
+
+ScConditionalFormat::ScConditionalFormat(sal_uInt32 nNewKey, ScDocument* pDocument) :
+ pDoc( pDocument ),
+ pAreas( NULL ),
+ nKey( nNewKey ),
+ ppEntries( NULL ),
+ nEntryCount( 0 )
+{
+}
+
+ScConditionalFormat::ScConditionalFormat(const ScConditionalFormat& r) :
+ pDoc( r.pDoc ),
+ pAreas( NULL ),
+ nKey( r.nKey ),
+ ppEntries( NULL ),
+ nEntryCount( r.nEntryCount )
+{
+ if (nEntryCount)
+ {
+ ppEntries = new ScCondFormatEntry*[nEntryCount];
+ for (USHORT i=0; i<nEntryCount; i++)
+ {
+ ppEntries[i] = new ScCondFormatEntry(*r.ppEntries[i]);
+ ppEntries[i]->SetParent(this);
+ }
+ }
+}
+
+ScConditionalFormat* ScConditionalFormat::Clone(ScDocument* pNewDoc) const
+{
+ // echte Kopie der Formeln (fuer Ref-Undo / zwischen Dokumenten)
+
+ if (!pNewDoc)
+ pNewDoc = pDoc;
+
+ ScConditionalFormat* pNew = new ScConditionalFormat(nKey, pNewDoc);
+ DBG_ASSERT(!pNew->ppEntries, "wo kommen die Eintraege her?");
+
+ if (nEntryCount)
+ {
+ pNew->ppEntries = new ScCondFormatEntry*[nEntryCount];
+ for (USHORT i=0; i<nEntryCount; i++)
+ {
+ pNew->ppEntries[i] = new ScCondFormatEntry( pNewDoc, *ppEntries[i] );
+ pNew->ppEntries[i]->SetParent(pNew);
+ }
+ pNew->nEntryCount = nEntryCount;
+ }
+
+ return pNew;
+}
+
+BOOL ScConditionalFormat::EqualEntries( const ScConditionalFormat& r ) const
+{
+ if ( nEntryCount != r.nEntryCount )
+ return FALSE;
+
+ //! auf gleiche Eintraege in anderer Reihenfolge testen ???
+
+ for (USHORT i=0; i<nEntryCount; i++)
+ if ( ! (*ppEntries[i] == *r.ppEntries[i]) )
+ return FALSE;
+
+ return TRUE;
+}
+
+void ScConditionalFormat::AddEntry( const ScCondFormatEntry& rNew )
+{
+ ScCondFormatEntry** ppNew = new ScCondFormatEntry*[nEntryCount+1];
+ for (USHORT i=0; i<nEntryCount; i++)
+ ppNew[i] = ppEntries[i];
+ ppNew[nEntryCount] = new ScCondFormatEntry(rNew);
+ ppNew[nEntryCount]->SetParent(this);
+ ++nEntryCount;
+ delete[] ppEntries;
+ ppEntries = ppNew;
+}
+
+ScConditionalFormat::~ScConditionalFormat()
+{
+ for (USHORT i=0; i<nEntryCount; i++)
+ delete ppEntries[i];
+ delete[] ppEntries;
+
+ delete pAreas;
+}
+
+const ScCondFormatEntry* ScConditionalFormat::GetEntry( USHORT nPos ) const
+{
+ if ( nPos < nEntryCount )
+ return ppEntries[nPos];
+ else
+ return NULL;
+}
+
+const String& ScConditionalFormat::GetCellStyle( ScBaseCell* pCell, const ScAddress& rPos ) const
+{
+ for (USHORT i=0; i<nEntryCount; i++)
+ if ( ppEntries[i]->IsCellValid( pCell, rPos ) )
+ return ppEntries[i]->GetStyle();
+
+ return EMPTY_STRING;
+}
+
+void lcl_Extend( ScRange& rRange, ScDocument* pDoc, BOOL bLines )
+{
+ SCTAB nTab = rRange.aStart.Tab();
+ DBG_ASSERT(rRange.aEnd.Tab() == nTab, "lcl_Extend - mehrere Tabellen?");
+
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+
+ BOOL bEx = pDoc->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab );
+
+ if (bLines)
+ {
+ if (nStartCol > 0) --nStartCol;
+ if (nStartRow > 0) --nStartRow;
+ if (nEndCol < MAXCOL) ++nEndCol;
+ if (nEndRow < MAXROW) ++nEndRow;
+ }
+
+ if ( bEx || bLines )
+ {
+ rRange.aStart.Set( nStartCol, nStartRow, nTab );
+ rRange.aEnd.Set( nEndCol, nEndRow, nTab );
+ }
+}
+
+BOOL lcl_CutRange( ScRange& rRange, const ScRange& rOther )
+{
+ rRange.Justify();
+ ScRange aCmpRange = rOther;
+ aCmpRange.Justify();
+
+ if ( rRange.aStart.Col() <= aCmpRange.aEnd.Col() &&
+ rRange.aEnd.Col() >= aCmpRange.aStart.Col() &&
+ rRange.aStart.Row() <= aCmpRange.aEnd.Row() &&
+ rRange.aEnd.Row() >= aCmpRange.aStart.Row() &&
+ rRange.aStart.Tab() <= aCmpRange.aEnd.Tab() &&
+ rRange.aEnd.Tab() >= aCmpRange.aStart.Tab() )
+ {
+ if ( rRange.aStart.Col() < aCmpRange.aStart.Col() )
+ rRange.aStart.SetCol( aCmpRange.aStart.Col() );
+ if ( rRange.aStart.Row() < aCmpRange.aStart.Row() )
+ rRange.aStart.SetRow( aCmpRange.aStart.Row() );
+ if ( rRange.aStart.Tab() < aCmpRange.aStart.Tab() )
+ rRange.aStart.SetTab( aCmpRange.aStart.Tab() );
+ if ( rRange.aEnd.Col() > aCmpRange.aEnd.Col() )
+ rRange.aEnd.SetCol( aCmpRange.aEnd.Col() );
+ if ( rRange.aEnd.Row() > aCmpRange.aEnd.Row() )
+ rRange.aEnd.SetRow( aCmpRange.aEnd.Row() );
+ if ( rRange.aEnd.Tab() > aCmpRange.aEnd.Tab() )
+ rRange.aEnd.SetTab( aCmpRange.aEnd.Tab() );
+
+ return TRUE;
+ }
+
+ return FALSE; // ausserhalb
+}
+
+void ScConditionalFormat::DoRepaint( const ScRange* pModified )
+{
+ USHORT i;
+ SfxObjectShell* pSh = pDoc->GetDocumentShell();
+ if (pSh)
+ {
+ // Rahmen/Schatten enthalten?
+ // (alle Bedingungen testen)
+ BOOL bExtend = FALSE;
+ BOOL bRotate = FALSE;
+ BOOL bAttrTested = FALSE;
+
+ if (!pAreas) // RangeList ggf. holen
+ {
+ pAreas = new ScRangeList;
+ pDoc->FindConditionalFormat( nKey, *pAreas );
+ }
+ USHORT nCount = (USHORT) pAreas->Count();
+ for (i=0; i<nCount; i++)
+ {
+ ScRange aRange = *pAreas->GetObject(i);
+ BOOL bDo = TRUE;
+ if ( pModified )
+ {
+ if ( !lcl_CutRange( aRange, *pModified ) )
+ bDo = FALSE;
+ }
+ if (bDo)
+ {
+ if ( !bAttrTested )
+ {
+ // #116562# Look at the style's content only if the repaint is necessary
+ // for any condition, to avoid the time-consuming Find() if there are many
+ // conditional formats and styles.
+ for (USHORT nEntry=0; nEntry<nEntryCount; nEntry++)
+ {
+ String aStyle = ppEntries[nEntry]->GetStyle();
+ if (aStyle.Len())
+ {
+ SfxStyleSheetBase* pStyleSheet =
+ pDoc->GetStyleSheetPool()->Find( aStyle, SFX_STYLE_FAMILY_PARA );
+ if ( pStyleSheet )
+ {
+ const SfxItemSet& rSet = pStyleSheet->GetItemSet();
+ if (rSet.GetItemState( ATTR_BORDER, TRUE ) == SFX_ITEM_SET ||
+ rSet.GetItemState( ATTR_SHADOW, TRUE ) == SFX_ITEM_SET)
+ {
+ bExtend = TRUE;
+ }
+ if (rSet.GetItemState( ATTR_ROTATE_VALUE, TRUE ) == SFX_ITEM_SET ||
+ rSet.GetItemState( ATTR_ROTATE_MODE, TRUE ) == SFX_ITEM_SET)
+ {
+ bRotate = TRUE;
+ }
+ }
+ }
+ }
+ bAttrTested = TRUE;
+ }
+
+ lcl_Extend( aRange, pDoc, bExtend ); // zusammengefasste und bExtend
+ if ( bRotate )
+ {
+ aRange.aStart.SetCol(0);
+ aRange.aEnd.SetCol(MAXCOL); // gedreht: ganze Zeilen
+ }
+
+ // gedreht -> ganze Zeilen
+ if ( aRange.aStart.Col() != 0 || aRange.aEnd.Col() != MAXCOL )
+ {
+ if ( pDoc->HasAttrib( 0,aRange.aStart.Row(),aRange.aStart.Tab(),
+ MAXCOL,aRange.aEnd.Row(),aRange.aEnd.Tab(),
+ HASATTR_ROTATE ) )
+ {
+ aRange.aStart.SetCol(0);
+ aRange.aEnd.SetCol(MAXCOL);
+ }
+ }
+
+ pSh->Broadcast( ScPaintHint( aRange, PAINT_GRID ) );
+ }
+ }
+ }
+}
+
+void ScConditionalFormat::InvalidateArea()
+{
+ delete pAreas;
+ pAreas = NULL;
+}
+
+void ScConditionalFormat::CompileAll()
+{
+ for (USHORT i=0; i<nEntryCount; i++)
+ ppEntries[i]->CompileAll();
+}
+
+void ScConditionalFormat::CompileXML()
+{
+ for (USHORT i=0; i<nEntryCount; i++)
+ ppEntries[i]->CompileXML();
+}
+
+void ScConditionalFormat::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ for (USHORT i=0; i<nEntryCount; i++)
+ ppEntries[i]->UpdateReference(eUpdateRefMode, rRange, nDx, nDy, nDz);
+
+ delete pAreas; // aus dem AttrArray kommt beim Einfuegen/Loeschen kein Aufruf
+ pAreas = NULL;
+}
+
+void ScConditionalFormat::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
+{
+ for (USHORT i=0; i<nEntryCount; i++)
+ ppEntries[i]->UpdateMoveTab( nOldPos, nNewPos );
+
+ delete pAreas; // aus dem AttrArray kommt beim Einfuegen/Loeschen kein Aufruf
+ pAreas = NULL;
+}
+
+void ScConditionalFormat::SourceChanged( const ScAddress& rAddr )
+{
+ for (USHORT i=0; i<nEntryCount; i++)
+ ppEntries[i]->SourceChanged( rAddr );
+}
+
+bool ScConditionalFormat::MarkUsedExternalReferences() const
+{
+ bool bAllMarked = false;
+ for (USHORT i=0; !bAllMarked && i<nEntryCount; i++)
+ bAllMarked = ppEntries[i]->MarkUsedExternalReferences();
+ return bAllMarked;
+}
+
+//------------------------------------------------------------------------
+
+ScConditionalFormatList::ScConditionalFormatList(const ScConditionalFormatList& rList) :
+ ScConditionalFormats_Impl()
+{
+ // fuer Ref-Undo - echte Kopie mit neuen Tokens!
+
+ USHORT nCount = rList.Count();
+
+ for (USHORT i=0; i<nCount; i++)
+ InsertNew( rList[i]->Clone() );
+
+ //! sortierte Eintraege aus rList schneller einfuegen ???
+}
+
+ScConditionalFormatList::ScConditionalFormatList(ScDocument* pNewDoc,
+ const ScConditionalFormatList& rList)
+{
+ // fuer neues Dokument - echte Kopie mit neuen Tokens!
+
+ USHORT nCount = rList.Count();
+
+ for (USHORT i=0; i<nCount; i++)
+ InsertNew( rList[i]->Clone(pNewDoc) );
+
+ //! sortierte Eintraege aus rList schneller einfuegen ???
+}
+
+BOOL ScConditionalFormatList::operator==( const ScConditionalFormatList& r ) const
+{
+ // fuer Ref-Undo - interne Variablen werden nicht verglichen
+
+ USHORT nCount = Count();
+ BOOL bEqual = ( nCount == r.Count() );
+ for (USHORT i=0; i<nCount && bEqual; i++) // Eintraege sind sortiert
+ if ( !(*this)[i]->EqualEntries(*r[i]) ) // Eintraege unterschiedlich ?
+ bEqual = FALSE;
+
+ return bEqual;
+}
+
+ScConditionalFormat* ScConditionalFormatList::GetFormat( sal_uInt32 nKey )
+{
+ //! binaer suchen
+
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ if ((*this)[i]->GetKey() == nKey)
+ return (*this)[i];
+
+ DBG_ERROR("ScConditionalFormatList: Eintrag nicht gefunden");
+ return NULL;
+}
+
+//UNUSED2008-05 void ScConditionalFormatList::ResetUsed()
+//UNUSED2008-05 {
+//UNUSED2008-05 USHORT nCount = Count();
+//UNUSED2008-05 for (USHORT i=0; i<nCount; i++)
+//UNUSED2008-05 (*this)[i]->SetUsed(FALSE);
+//UNUSED2008-05 }
+
+void ScConditionalFormatList::CompileAll()
+{
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ (*this)[i]->CompileAll();
+}
+
+void ScConditionalFormatList::CompileXML()
+{
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ (*this)[i]->CompileXML();
+}
+
+void ScConditionalFormatList::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ (*this)[i]->UpdateReference( eUpdateRefMode, rRange, nDx, nDy, nDz );
+}
+
+void ScConditionalFormatList::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
+{
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ (*this)[i]->UpdateMoveTab( nOldPos, nNewPos );
+}
+
+void ScConditionalFormatList::SourceChanged( const ScAddress& rAddr )
+{
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ (*this)[i]->SourceChanged( rAddr );
+}
+
+bool ScConditionalFormatList::MarkUsedExternalReferences() const
+{
+ bool bAllMarked = false;
+ USHORT nCount = Count();
+ for (USHORT i=0; !bAllMarked && i<nCount; i++)
+ bAllMarked = (*this)[i]->MarkUsedExternalReferences();
+ return bAllMarked;
+}
diff --git a/sc/source/core/data/dbdocutl.cxx b/sc/source/core/data/dbdocutl.cxx
new file mode 100644
index 000000000000..6a849282a642
--- /dev/null
+++ b/sc/source/core/data/dbdocutl.cxx
@@ -0,0 +1,200 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dbdocutl.cxx,v $
+ * $Revision: 1.9 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+
+#include <svtools/zforlist.hxx>
+
+#include "dbdocutl.hxx"
+#include "document.hxx"
+#include "cell.hxx"
+#include "formula/errorcodes.hxx"
+
+using namespace ::com::sun::star;
+
+#define D_TIMEFACTOR 86400.0
+
+// -----------------------------------------------------------------------
+
+// static
+void ScDatabaseDocUtil::PutData( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab,
+ const uno::Reference<sdbc::XRow>& xRow, long nRowPos,
+ long nType, BOOL bCurrency, BOOL* pSimpleFlag )
+{
+ String aString;
+ double nVal = 0.0;
+ BOOL bValue = FALSE;
+ BOOL bEmptyFlag = FALSE;
+ BOOL bError = FALSE;
+ ULONG nFormatIndex = 0;
+
+ //! wasNull calls only if null value was found?
+
+ try
+ {
+ switch ( nType )
+ {
+ case sdbc::DataType::BIT:
+ case sdbc::DataType::BOOLEAN:
+ //! use language from doc (here, date/time and currency)?
+ nFormatIndex = pDoc->GetFormatTable()->GetStandardFormat(
+ NUMBERFORMAT_LOGICAL, ScGlobal::eLnge );
+ nVal = (xRow->getBoolean(nRowPos) ? 1 : 0);
+ bEmptyFlag = ( nVal == 0.0 ) && xRow->wasNull();
+ bValue = TRUE;
+ break;
+
+ case sdbc::DataType::TINYINT:
+ case sdbc::DataType::SMALLINT:
+ case sdbc::DataType::INTEGER:
+ case sdbc::DataType::BIGINT:
+ case sdbc::DataType::FLOAT:
+ case sdbc::DataType::REAL:
+ case sdbc::DataType::DOUBLE:
+ case sdbc::DataType::NUMERIC:
+ case sdbc::DataType::DECIMAL:
+ //! do the conversion here?
+ nVal = xRow->getDouble(nRowPos);
+ bEmptyFlag = ( nVal == 0.0 ) && xRow->wasNull();
+ bValue = TRUE;
+ break;
+
+ case sdbc::DataType::CHAR:
+ case sdbc::DataType::VARCHAR:
+ case sdbc::DataType::LONGVARCHAR:
+ aString = xRow->getString(nRowPos);
+ bEmptyFlag = ( aString.Len() == 0 ) && xRow->wasNull();
+ break;
+
+ case sdbc::DataType::DATE:
+ {
+ SvNumberFormatter* pFormTable = pDoc->GetFormatTable();
+ nFormatIndex = pFormTable->GetStandardFormat(
+ NUMBERFORMAT_DATE, ScGlobal::eLnge );
+
+ util::Date aDate = xRow->getDate(nRowPos);
+ nVal = Date( aDate.Day, aDate.Month, aDate.Year ) -
+ *pFormTable->GetNullDate();
+ bEmptyFlag = xRow->wasNull();
+ bValue = TRUE;
+ }
+ break;
+
+ case sdbc::DataType::TIME:
+ {
+ SvNumberFormatter* pFormTable = pDoc->GetFormatTable();
+ nFormatIndex = pFormTable->GetStandardFormat(
+ NUMBERFORMAT_TIME, ScGlobal::eLnge );
+
+ util::Time aTime = xRow->getTime(nRowPos);
+ nVal = ( aTime.Hours * 3600 + aTime.Minutes * 60 +
+ aTime.Seconds + aTime.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
+ bEmptyFlag = xRow->wasNull();
+ bValue = TRUE;
+ }
+ break;
+
+ case sdbc::DataType::TIMESTAMP:
+ {
+ SvNumberFormatter* pFormTable = pDoc->GetFormatTable();
+ nFormatIndex = pFormTable->GetStandardFormat(
+ NUMBERFORMAT_DATETIME, ScGlobal::eLnge );
+
+ util::DateTime aStamp = xRow->getTimestamp(nRowPos);
+ nVal = ( Date( aStamp.Day, aStamp.Month, aStamp.Year ) -
+ *pFormTable->GetNullDate() ) +
+ ( aStamp.Hours * 3600 + aStamp.Minutes * 60 +
+ aStamp.Seconds + aStamp.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
+ bEmptyFlag = xRow->wasNull();
+ bValue = TRUE;
+ }
+ break;
+
+ case sdbc::DataType::SQLNULL:
+ bEmptyFlag = TRUE;
+ break;
+
+ case sdbc::DataType::BINARY:
+ case sdbc::DataType::VARBINARY:
+ case sdbc::DataType::LONGVARBINARY:
+ default:
+ bError = TRUE; // unknown type
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ bError = TRUE;
+ }
+
+ if ( bValue && bCurrency )
+ nFormatIndex = pDoc->GetFormatTable()->GetStandardFormat(
+ NUMBERFORMAT_CURRENCY, ScGlobal::eLnge );
+
+ ScBaseCell* pCell;
+ if (bEmptyFlag)
+ {
+ pCell = NULL;
+ pDoc->PutCell( nCol, nRow, nTab, pCell );
+ }
+ else if (bError)
+ {
+ pDoc->SetError( nCol, nRow, nTab, NOTAVAILABLE );
+ }
+ else if (bValue)
+ {
+ pCell = new ScValueCell( nVal );
+ if (nFormatIndex == 0)
+ pDoc->PutCell( nCol, nRow, nTab, pCell );
+ else
+ pDoc->PutCell( nCol, nRow, nTab, pCell, nFormatIndex );
+ }
+ else
+ {
+ if (aString.Len())
+ {
+ pCell = ScBaseCell::CreateTextCell( aString, pDoc );
+ if ( pSimpleFlag && pCell->GetCellType() == CELLTYPE_EDIT )
+ *pSimpleFlag = FALSE;
+ }
+ else
+ pCell = NULL;
+ pDoc->PutCell( nCol, nRow, nTab, pCell );
+ }
+}
+
+
diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
new file mode 100644
index 000000000000..3b650f5d8ca4
--- /dev/null
+++ b/sc/source/core/data/dociter.cxx
@@ -0,0 +1,1803 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dociter.cxx,v $
+ * $Revision: 1.22.88.2 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <svtools/zforlist.hxx>
+
+#include "scitems.hxx"
+#include "global.hxx"
+#include "dociter.hxx"
+#include "document.hxx"
+#include "table.hxx"
+#include "column.hxx"
+#include "cell.hxx"
+#include "attarray.hxx"
+#include "patattr.hxx"
+#include "docoptio.hxx"
+#include "cellform.hxx"
+
+
+// STATIC DATA -----------------------------------------------------------
+
+ScDocumentIterator::ScDocumentIterator( ScDocument* pDocument,
+ SCTAB nStartTable, SCTAB nEndTable ) :
+ pDoc( pDocument ),
+ nStartTab( nStartTable ),
+ nEndTab( nEndTable )
+{
+ PutInOrder( nStartTab, nEndTab );
+ if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
+ if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
+
+ pDefPattern = pDoc->GetDefPattern();
+
+ nCol = 0;
+ nRow = 0;
+ nTab = nStartTab;
+
+ nColPos = 0;
+ nAttrPos = 0;
+}
+
+ScDocumentIterator::~ScDocumentIterator()
+{
+}
+
+BOOL ScDocumentIterator::GetThisCol()
+{
+ ScTable* pTab;
+ while ( (pTab = pDoc->pTab[nTab]) == NULL )
+ {
+ if ( nTab == nEndTab )
+ {
+ nCol = MAXCOL;
+ nRow = MAXROW;
+ return FALSE;
+ }
+ ++nTab;
+ }
+ ScColumn* pCol = &pTab->aCol[nCol];
+ ScAttrArray* pAtt = pCol->pAttrArray;
+
+ BOOL bFound = FALSE;
+ do
+ {
+ SCROW nColRow;
+ SCROW nAttrEnd;
+
+ do
+ {
+ nAttrEnd = pAtt->pData[nAttrPos].nRow;
+ if (nAttrEnd < nRow)
+ ++nAttrPos;
+ }
+ while (nAttrEnd < nRow);
+
+ do
+ {
+ nColRow = (nColPos < pCol->nCount) ? pCol->pItems[nColPos].nRow : MAXROW+1;
+ if (nColRow < nRow)
+ ++nColPos;
+ }
+ while (nColRow < nRow);
+
+ if (nColRow == nRow)
+ {
+ bFound = TRUE;
+ pCell = pCol->pItems[nColPos].pCell;
+ pPattern = pAtt->pData[nAttrPos].pPattern;
+ }
+ else if ( pAtt->pData[nAttrPos].pPattern != pDefPattern )
+ {
+ bFound = TRUE;
+ pCell = NULL;
+ pPattern = pAtt->pData[nAttrPos].pPattern;
+ }
+ else
+ {
+ nRow = Min( (SCROW)nColRow, (SCROW)(nAttrEnd+1) );
+ }
+ }
+ while (!bFound && nRow <= MAXROW);
+
+ return bFound;
+}
+
+BOOL ScDocumentIterator::GetThis()
+{
+ BOOL bEnd = FALSE;
+ BOOL bSuccess = FALSE;
+
+ while ( !bSuccess && !bEnd )
+ {
+ if ( nRow > MAXROW )
+ bSuccess = FALSE;
+ else
+ bSuccess = GetThisCol();
+
+ if ( !bSuccess )
+ {
+ ++nCol;
+ if (nCol > MAXCOL)
+ {
+ nCol = 0;
+ ++nTab;
+ if (nTab > nEndTab)
+ bEnd = TRUE;
+ }
+ nRow = 0;
+ nColPos = 0;
+ nAttrPos = 0;
+ }
+ }
+
+ return !bEnd;
+}
+
+BOOL ScDocumentIterator::GetFirst()
+{
+ nCol = 0;
+ nTab = nStartTab;
+
+ nRow = 0;
+ nColPos = 0;
+ nAttrPos = 0;
+
+ return GetThis();
+}
+
+BOOL ScDocumentIterator::GetNext()
+{
+ ++nRow;
+
+ return GetThis();
+}
+
+//------------------------------------------------------------------------
+
+ScBaseCell* ScDocumentIterator::GetCell()
+{
+ return pCell;
+}
+
+const ScPatternAttr* ScDocumentIterator::GetPattern()
+{
+ return pPattern;
+}
+
+void ScDocumentIterator::GetPos( SCCOL& rCol, SCROW& rRow, SCTAB& rTab )
+{
+ rCol = nCol;
+ rRow = nRow;
+ rTab = nTab;
+}
+
+
+//------------------------------------------------------------------------
+//------------------------------------------------------------------------
+void lcl_IterGetNumberFormat( ULONG& nFormat, const ScAttrArray*& rpArr,
+ SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow,
+ ScDocument* pDoc )
+{
+ if ( rpArr != pNewArr || nAttrEndRow < nRow )
+ {
+ SCSIZE nPos;
+ pNewArr->Search( nRow, nPos ); // nPos 0 gueltig wenn nicht gefunden
+ const ScPatternAttr* pPattern = pNewArr->pData[nPos].pPattern;
+ nFormat = pPattern->GetNumberFormat( pDoc->GetFormatTable() );
+ rpArr = pNewArr;
+ nAttrEndRow = pNewArr->pData[nPos].nRow;
+ }
+}
+
+//UNUSED2008-05 ScValueIterator::ScValueIterator( ScDocument* pDocument,
+//UNUSED2008-05 SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
+//UNUSED2008-05 SCCOL nECol, SCROW nERow, SCTAB nETab,
+//UNUSED2008-05 BOOL bSTotal, BOOL bTextZero ) :
+//UNUSED2008-05 pDoc( pDocument ),
+//UNUSED2008-05 nNumFmtIndex(0),
+//UNUSED2008-05 nStartCol( nSCol),
+//UNUSED2008-05 nStartRow( nSRow),
+//UNUSED2008-05 nStartTab( nSTab ),
+//UNUSED2008-05 nEndCol( nECol ),
+//UNUSED2008-05 nEndRow( nERow),
+//UNUSED2008-05 nEndTab( nETab ),
+//UNUSED2008-05 nNumFmtType( NUMBERFORMAT_UNDEFINED ),
+//UNUSED2008-05 bNumValid( FALSE ),
+//UNUSED2008-05 bSubTotal(bSTotal),
+//UNUSED2008-05 bNextValid( FALSE ),
+//UNUSED2008-05 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
+//UNUSED2008-05 bTextAsZero( bTextZero )
+//UNUSED2008-05 {
+//UNUSED2008-05 PutInOrder( nStartCol, nEndCol);
+//UNUSED2008-05 PutInOrder( nStartRow, nEndRow);
+//UNUSED2008-05 PutInOrder( nStartTab, nEndTab );
+//UNUSED2008-05
+//UNUSED2008-05 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
+//UNUSED2008-05 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
+//UNUSED2008-05 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
+//UNUSED2008-05 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
+//UNUSED2008-05 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
+//UNUSED2008-05 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
+//UNUSED2008-05
+//UNUSED2008-05 nCol = nStartCol;
+//UNUSED2008-05 nRow = nStartRow;
+//UNUSED2008-05 nTab = nStartTab;
+//UNUSED2008-05
+//UNUSED2008-05 nColRow = 0; // wird bei GetFirst initialisiert
+//UNUSED2008-05
+//UNUSED2008-05 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
+//UNUSED2008-05 pAttrArray = 0;
+//UNUSED2008-05 nAttrEndRow = 0;
+//UNUSED2008-05 }
+
+ScValueIterator::ScValueIterator( ScDocument* pDocument, const ScRange& rRange,
+ BOOL bSTotal, BOOL bTextZero ) :
+ pDoc( pDocument ),
+ nNumFmtIndex(0),
+ nStartCol( rRange.aStart.Col() ),
+ nStartRow( rRange.aStart.Row() ),
+ nStartTab( rRange.aStart.Tab() ),
+ nEndCol( rRange.aEnd.Col() ),
+ nEndRow( rRange.aEnd.Row() ),
+ nEndTab( rRange.aEnd.Tab() ),
+ nNumFmtType( NUMBERFORMAT_UNDEFINED ),
+ bNumValid( FALSE ),
+ bSubTotal(bSTotal),
+ bNextValid( FALSE ),
+ bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
+ bTextAsZero( bTextZero )
+{
+ PutInOrder( nStartCol, nEndCol);
+ PutInOrder( nStartRow, nEndRow);
+ PutInOrder( nStartTab, nEndTab );
+
+ if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
+ if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
+ if (!ValidRow(nStartRow)) nStartRow = MAXROW;
+ if (!ValidRow(nEndRow)) nEndRow = MAXROW;
+ if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
+ if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
+
+ nCol = nStartCol;
+ nRow = nStartRow;
+ nTab = nStartTab;
+
+ nColRow = 0; // wird bei GetFirst initialisiert
+
+ nNumFormat = 0; // werden bei GetNumberFormat initialisiert
+ pAttrArray = 0;
+ nAttrEndRow = 0;
+}
+
+BOOL ScValueIterator::GetThis(double& rValue, USHORT& rErr)
+{
+ ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ for (;;)
+ {
+ if ( nRow > nEndRow )
+ {
+ nRow = nStartRow;
+ do
+ {
+ nCol++;
+ if ( nCol > nEndCol )
+ {
+ nCol = nStartCol;
+ nTab++;
+ if ( nTab > nEndTab )
+ {
+ // rValue = 0.0; //! do not change caller's value!
+ rErr = 0;
+ return FALSE; // Ende und Aus
+ }
+ }
+ pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ } while ( pCol->nCount == 0 );
+ pCol->Search( nRow, nColRow );
+ }
+
+ while (( nColRow < pCol->nCount ) && ( pCol->pItems[nColRow].nRow < nRow ))
+ nColRow++;
+
+ if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow )
+ {
+ nRow = pCol->pItems[nColRow].nRow + 1;
+ if ( !bSubTotal || !pDoc->pTab[nTab]->IsFiltered( nRow-1 ) )
+ {
+ ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
+ ++nColRow;
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ {
+ bNumValid = FALSE;
+ rValue = ((ScValueCell*)pCell)->GetValue();
+ rErr = 0;
+ --nRow;
+ if ( bCalcAsShown )
+ {
+ lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
+ nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
+ rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
+ }
+ //
+ // wenn in der selben Spalte gleich noch eine Value-Cell folgt, die
+ // auch noch im Block liegt, den Wert jetzt schon holen
+ //
+ if ( nColRow < pCol->nCount &&
+ pCol->pItems[nColRow].nRow <= nEndRow &&
+ pCol->pItems[nColRow].pCell->GetCellType() == CELLTYPE_VALUE &&
+ !bSubTotal )
+ {
+ fNextValue = ((ScValueCell*)pCol->pItems[nColRow].pCell)->GetValue();
+ nNextRow = pCol->pItems[nColRow].nRow;
+ bNextValid = TRUE;
+ if ( bCalcAsShown )
+ {
+ lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
+ nAttrEndRow, pCol->pAttrArray, nNextRow, pDoc );
+ fNextValue = pDoc->RoundValueAsShown( fNextValue, nNumFormat );
+ }
+ }
+
+ return TRUE; // gefunden
+ }
+// break;
+ case CELLTYPE_FORMULA:
+ {
+ if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal())
+ {
+ rErr = ((ScFormulaCell*)pCell)->GetErrCode();
+ if ( rErr || ((ScFormulaCell*)pCell)->IsValue() )
+ {
+ rValue = ((ScFormulaCell*)pCell)->GetValue();
+ nRow--;
+ bNumValid = FALSE;
+ return TRUE; // gefunden
+ }
+ else if ( bTextAsZero )
+ {
+ rValue = 0.0;
+ nRow--;
+ bNumValid = FALSE;
+ return TRUE;
+ }
+ }
+ }
+ break;
+ case CELLTYPE_STRING :
+ case CELLTYPE_EDIT :
+ {
+ if ( bTextAsZero )
+ {
+ rErr = 0;
+ rValue = 0.0;
+ nNumFmtType = NUMBERFORMAT_NUMBER;
+ nNumFmtIndex = 0;
+ bNumValid = TRUE;
+ --nRow;
+ return TRUE;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ else
+ nRow = nEndRow + 1; // naechste Spalte
+ }
+}
+
+void ScValueIterator::GetCurNumFmtInfo( short& nType, ULONG& nIndex )
+{
+ if (!bNumValid)
+ {
+ const ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ nNumFmtIndex = pCol->GetNumberFormat( nRow );
+ if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
+ {
+ const ScBaseCell* pCell;
+ SCSIZE nIdx = nColRow - 1;
+ // there might be rearranged something, so be on the safe side
+ if ( nIdx < pCol->nCount && pCol->pItems[nIdx].nRow == nRow )
+ pCell = pCol->pItems[nIdx].pCell;
+ else
+ {
+ if ( pCol->Search( nRow, nIdx ) )
+ pCell = pCol->pItems[nIdx].pCell;
+ else
+ pCell = NULL;
+ }
+ if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
+ ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex );
+ else
+ nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
+ }
+ else
+ nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
+ bNumValid = TRUE;
+ }
+ nType = nNumFmtType;
+ nIndex = nNumFmtIndex;
+}
+
+BOOL ScValueIterator::GetFirst(double& rValue, USHORT& rErr)
+{
+ nCol = nStartCol;
+ nRow = nStartRow;
+ nTab = nStartTab;
+
+// nColRow = 0;
+ ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ pCol->Search( nRow, nColRow );
+
+ nNumFormat = 0; // werden bei GetNumberFormat initialisiert
+ pAttrArray = 0;
+ nAttrEndRow = 0;
+
+ return GetThis(rValue, rErr);
+}
+
+/* ist inline:
+BOOL ScValueIterator::GetNext(double& rValue, USHORT& rErr)
+{
+ ++nRow;
+ return GetThis(rValue, rErr);
+}
+*/
+
+//------------------------------------------------------------------------
+//------------------------------------------------------------------------
+
+ScQueryValueIterator::ScQueryValueIterator(ScDocument* pDocument, SCTAB nTable, const ScQueryParam& rParam) :
+ aParam (rParam),
+ pDoc( pDocument ),
+ nNumFmtIndex(0),
+ nTab( nTable),
+ nNumFmtType( NUMBERFORMAT_UNDEFINED ),
+ bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() )
+{
+ nCol = aParam.nCol1;
+ nRow = aParam.nRow1;
+ nColRow = 0; // wird bei GetFirst initialisiert
+ SCSIZE i;
+ SCSIZE nCount = aParam.GetEntryCount();
+ for (i=0; (i<nCount) && (aParam.GetEntry(i).bDoQuery); i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ sal_uInt32 nIndex = 0;
+ rEntry.bQueryByString =
+ !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal));
+ }
+ nNumFormat = 0; // werden bei GetNumberFormat initialisiert
+ pAttrArray = 0;
+ nAttrEndRow = 0;
+}
+
+BOOL ScQueryValueIterator::GetThis(double& rValue, USHORT& rErr)
+{
+ ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ SCCOLROW nFirstQueryField = aParam.GetEntry(0).nField;
+ for ( ;; )
+ {
+ if ( nRow > aParam.nRow2 )
+ {
+ nRow = aParam.nRow1;
+ if (aParam.bHasHeader)
+ nRow++;
+ do
+ {
+ nCol++;
+ if ( nCol > aParam.nCol2 )
+ {
+ // rValue = 0.0; // do not change caller's value!
+ rErr = 0;
+ return FALSE; // Ende und Aus
+ }
+ pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ } while ( pCol->nCount == 0 );
+ pCol->Search( nRow, nColRow );
+ }
+
+ while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) )
+ nColRow++;
+
+ if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= aParam.nRow2 )
+ {
+ nRow = pCol->pItems[nColRow].nRow;
+ ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
+ if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL,
+ (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL) ) )
+ {
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ {
+ rValue = ((ScValueCell*)pCell)->GetValue();
+ if ( bCalcAsShown )
+ {
+ lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
+ nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
+ rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
+ }
+ nNumFmtType = NUMBERFORMAT_NUMBER;
+ nNumFmtIndex = 0;
+ rErr = 0;
+ return TRUE; // gefunden
+ }
+// break;
+ case CELLTYPE_FORMULA:
+ {
+ if (((ScFormulaCell*)pCell)->IsValue())
+ {
+ rValue = ((ScFormulaCell*)pCell)->GetValue();
+ pDoc->GetNumberFormatInfo( nNumFmtType,
+ nNumFmtIndex, ScAddress( nCol, nRow, nTab ),
+ pCell );
+ rErr = ((ScFormulaCell*)pCell)->GetErrCode();
+ return TRUE; // gefunden
+ }
+ else
+ nRow++;
+ }
+ break;
+ default:
+ nRow++;
+ break;
+ }
+ }
+ else
+ nRow++;
+ }
+ else
+ nRow = aParam.nRow2 + 1; // Naechste Spalte
+ }
+// return FALSE;
+}
+
+BOOL ScQueryValueIterator::GetFirst(double& rValue, USHORT& rErr)
+{
+ nCol = aParam.nCol1;
+ nRow = aParam.nRow1;
+ if (aParam.bHasHeader)
+ nRow++;
+// nColRow = 0;
+ ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ pCol->Search( nRow, nColRow );
+ return GetThis(rValue, rErr);
+}
+
+BOOL ScQueryValueIterator::GetNext(double& rValue, USHORT& rErr)
+{
+ ++nRow;
+ return GetThis(rValue, rErr);
+}
+
+//-------------------------------------------------------------------------------
+
+ScCellIterator::ScCellIterator( ScDocument* pDocument,
+ SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
+ SCCOL nECol, SCROW nERow, SCTAB nETab, BOOL bSTotal ) :
+ pDoc( pDocument ),
+ nStartCol( nSCol),
+ nStartRow( nSRow),
+ nStartTab( nSTab ),
+ nEndCol( nECol ),
+ nEndRow( nERow),
+ nEndTab( nETab ),
+ bSubTotal(bSTotal)
+
+{
+ PutInOrder( nStartCol, nEndCol);
+ PutInOrder( nStartRow, nEndRow);
+ PutInOrder( nStartTab, nEndTab );
+
+ if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
+ if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
+ if (!ValidRow(nStartRow)) nStartRow = MAXROW;
+ if (!ValidRow(nEndRow)) nEndRow = MAXROW;
+ if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
+ if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
+
+ while (nEndTab>0 && !pDoc->pTab[nEndTab])
+ --nEndTab; // nur benutzte Tabellen
+ if (nStartTab>nEndTab)
+ nStartTab = nEndTab;
+
+ nCol = nStartCol;
+ nRow = nStartRow;
+ nTab = nStartTab;
+ nColRow = 0; // wird bei GetFirst initialisiert
+
+ if (!pDoc->pTab[nTab])
+ {
+ DBG_ERROR("Tabelle nicht gefunden");
+ nStartCol = nCol = MAXCOL+1;
+ nStartRow = nRow = MAXROW+1;
+ nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst
+ }
+}
+
+ScCellIterator::ScCellIterator
+ ( ScDocument* pDocument, const ScRange& rRange, BOOL bSTotal ) :
+ pDoc( pDocument ),
+ nStartCol( rRange.aStart.Col() ),
+ nStartRow( rRange.aStart.Row() ),
+ nStartTab( rRange.aStart.Tab() ),
+ nEndCol( rRange.aEnd.Col() ),
+ nEndRow( rRange.aEnd.Row() ),
+ nEndTab( rRange.aEnd.Tab() ),
+ bSubTotal(bSTotal)
+
+{
+ PutInOrder( nStartCol, nEndCol);
+ PutInOrder( nStartRow, nEndRow);
+ PutInOrder( nStartTab, nEndTab );
+
+ if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
+ if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
+ if (!ValidRow(nStartRow)) nStartRow = MAXROW;
+ if (!ValidRow(nEndRow)) nEndRow = MAXROW;
+ if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
+ if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
+
+ while (nEndTab>0 && !pDoc->pTab[nEndTab])
+ --nEndTab; // nur benutzte Tabellen
+ if (nStartTab>nEndTab)
+ nStartTab = nEndTab;
+
+ nCol = nStartCol;
+ nRow = nStartRow;
+ nTab = nStartTab;
+ nColRow = 0; // wird bei GetFirst initialisiert
+
+ if (!pDoc->pTab[nTab])
+ {
+ DBG_ERROR("Tabelle nicht gefunden");
+ nStartCol = nCol = MAXCOL+1;
+ nStartRow = nRow = MAXROW+1;
+ nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst
+ }
+}
+
+ScBaseCell* ScCellIterator::GetThis()
+{
+ ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ for ( ;; )
+ {
+ if ( nRow > nEndRow )
+ {
+ nRow = nStartRow;
+ do
+ {
+ nCol++;
+ if ( nCol > nEndCol )
+ {
+ nCol = nStartCol;
+ nTab++;
+ if ( nTab > nEndTab )
+ return NULL; // Ende und Aus
+ }
+ pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ } while ( pCol->nCount == 0 );
+ pCol->Search( nRow, nColRow );
+ }
+
+ while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) )
+ nColRow++;
+
+ if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow )
+ {
+ nRow = pCol->pItems[nColRow].nRow;
+ if ( !bSubTotal || !pDoc->pTab[nTab]->IsFiltered( nRow ) )
+ {
+ ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
+
+ if ( bSubTotal && pCell->GetCellType() == CELLTYPE_FORMULA
+ && ((ScFormulaCell*)pCell)->IsSubTotal() )
+ nRow++; // Sub-Total-Zeilen nicht
+ else
+ return pCell; // gefunden
+ }
+ else
+ nRow++;
+ }
+ else
+ nRow = nEndRow + 1; // Naechste Spalte
+ }
+}
+
+ScBaseCell* ScCellIterator::GetFirst()
+{
+ if ( !ValidTab(nTab) )
+ return NULL;
+ nCol = nStartCol;
+ nRow = nStartRow;
+ nTab = nStartTab;
+// nColRow = 0;
+ ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ pCol->Search( nRow, nColRow );
+ return GetThis();
+}
+
+ScBaseCell* ScCellIterator::GetNext()
+{
+ ++nRow;
+ return GetThis();
+}
+
+//-------------------------------------------------------------------------------
+
+ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
+ const ScQueryParam& rParam, BOOL bMod ) :
+ aParam (rParam),
+ pDoc( pDocument ),
+ nTab( nTable),
+ nStopOnMismatch( nStopOnMismatchDisabled ),
+ nTestEqualCondition( nTestEqualConditionDisabled ),
+ bAdvanceQuery( FALSE ),
+ bIgnoreMismatchOnLeadingStrings( FALSE )
+{
+ nCol = aParam.nCol1;
+ nRow = aParam.nRow1;
+ nColRow = 0; // wird bei GetFirst initialisiert
+ SCSIZE i;
+ if (bMod) // sonst schon eingetragen
+ {
+ for (i=0; (i<MAXQUERY) && (aParam.GetEntry(i).bDoQuery); i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ sal_uInt32 nIndex = 0;
+ rEntry.bQueryByString =
+ !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr,
+ nIndex, rEntry.nVal));
+ }
+ }
+ nNumFormat = 0; // werden bei GetNumberFormat initialisiert
+ pAttrArray = 0;
+ nAttrEndRow = 0;
+}
+
+ScBaseCell* ScQueryCellIterator::GetThis()
+{
+ ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ const ScQueryEntry& rEntry = aParam.GetEntry(0);
+ SCCOLROW nFirstQueryField = rEntry.nField;
+ bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
+ !rEntry.bQueryByString;
+ bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
+ !aParam.bHasHeader && rEntry.bQueryByString &&
+ ((aParam.bByRow && nRow == aParam.nRow1) ||
+ (!aParam.bByRow && nCol == aParam.nCol1));
+ for ( ;; )
+ {
+ if ( nRow > aParam.nRow2 )
+ {
+ nRow = aParam.nRow1;
+ if (aParam.bHasHeader && aParam.bByRow)
+ nRow++;
+ do
+ {
+ if ( ++nCol > aParam.nCol2 )
+ return NULL; // Ende und Aus
+ if ( bAdvanceQuery )
+ {
+ AdvanceQueryParamEntryField();
+ nFirstQueryField = rEntry.nField;
+ }
+ pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ } while ( pCol->nCount == 0 );
+ pCol->Search( nRow, nColRow );
+ bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
+ !aParam.bHasHeader && rEntry.bQueryByString &&
+ aParam.bByRow;
+ }
+
+ while ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow < nRow )
+ nColRow++;
+
+ if ( nColRow < pCol->nCount &&
+ (nRow = pCol->pItems[nColRow].nRow) <= aParam.nRow2 )
+ {
+ ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
+ if ( pCell->GetCellType() == CELLTYPE_NOTE )
+ ++nRow;
+ else if (bAllStringIgnore && pCell->HasStringData())
+ ++nRow;
+ else
+ {
+ BOOL bTestEqualCondition;
+ if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL,
+ (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL),
+ (nTestEqualCondition ? &bTestEqualCondition : NULL) ) )
+ {
+ if ( nTestEqualCondition && bTestEqualCondition )
+ nTestEqualCondition |= nTestEqualConditionMatched;
+ return pCell; // found
+ }
+ else if ( nStopOnMismatch )
+ {
+ // Yes, even a mismatch may have a fulfilled equal
+ // condition if regular expressions were involved and
+ // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
+ if ( nTestEqualCondition && bTestEqualCondition )
+ {
+ nTestEqualCondition |= nTestEqualConditionMatched;
+ nStopOnMismatch |= nStopOnMismatchOccured;
+ return NULL;
+ }
+ bool bStop;
+ if (bFirstStringIgnore)
+ {
+ if (pCell->HasStringData())
+ {
+ ++nRow;
+ bStop = false;
+ }
+ else
+ bStop = true;
+ }
+ else
+ bStop = true;
+ if (bStop)
+ {
+ nStopOnMismatch |= nStopOnMismatchOccured;
+ return NULL;
+ }
+ }
+ else
+ nRow++;
+ }
+ }
+ else
+ nRow = aParam.nRow2 + 1; // Naechste Spalte
+ bFirstStringIgnore = false;
+ }
+}
+
+ScBaseCell* ScQueryCellIterator::GetFirst()
+{
+ nCol = aParam.nCol1;
+ nRow = aParam.nRow1;
+ if (aParam.bHasHeader)
+ nRow++;
+// nColRow = 0;
+ ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ pCol->Search( nRow, nColRow );
+ return GetThis();
+}
+
+ScBaseCell* ScQueryCellIterator::GetNext()
+{
+ ++nRow;
+ if ( nStopOnMismatch )
+ nStopOnMismatch = nStopOnMismatchEnabled;
+ if ( nTestEqualCondition )
+ nTestEqualCondition = nTestEqualConditionEnabled;
+ return GetThis();
+}
+
+ULONG ScQueryCellIterator::GetNumberFormat()
+{
+ ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
+ nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
+ return nNumFormat;
+}
+
+void ScQueryCellIterator::AdvanceQueryParamEntryField()
+{
+ SCSIZE nEntries = aParam.GetEntryCount();
+ for ( SCSIZE j = 0; j < nEntries; j++ )
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry( j );
+ if ( rEntry.bDoQuery )
+ {
+ if ( rEntry.nField < MAXCOL )
+ rEntry.nField++;
+ else
+ {
+ DBG_ERRORFILE( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
+ }
+ }
+ else
+ break; // for
+ }
+}
+
+
+BOOL ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
+ SCROW& nFoundRow, BOOL bSearchForEqualAfterMismatch,
+ BOOL bIgnoreMismatchOnLeadingStringsP )
+{
+ nFoundCol = MAXCOL+1;
+ nFoundRow = MAXROW+1;
+ SetStopOnMismatch( TRUE ); // assume sorted keys
+ SetTestEqualCondition( TRUE );
+ bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP;
+ bool bRegExp = aParam.bRegExp && aParam.GetEntry(0).bQueryByString;
+ bool bBinary = !bRegExp && aParam.bByRow && (aParam.GetEntry(0).eOp ==
+ SC_LESS_EQUAL || aParam.GetEntry(0).eOp == SC_GREATER_EQUAL);
+ if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst())
+ {
+ // First equal entry or last smaller than (greater than) entry.
+ SCSIZE nColRowSave;
+ ScBaseCell* pNext = 0;
+ do
+ {
+ nFoundCol = GetCol();
+ nFoundRow = GetRow();
+ nColRowSave = nColRow;
+ } while ( !IsEqualConditionFulfilled() && (pNext = GetNext()) != NULL );
+ // There may be no pNext but equal condition fulfilled if regular
+ // expressions are involved. Keep the found entry and proceed.
+ if (!pNext && !IsEqualConditionFulfilled())
+ {
+ // Step back to last in range and adjust position markers for
+ // GetNumberFormat() or similar.
+ nCol = nFoundCol;
+ nRow = nFoundRow;
+ nColRow = nColRowSave;
+ }
+ }
+ if ( IsEqualConditionFulfilled() )
+ {
+ // Position on last equal entry.
+ SCSIZE nEntries = aParam.GetEntryCount();
+ for ( SCSIZE j = 0; j < nEntries; j++ )
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry( j );
+ if ( rEntry.bDoQuery )
+ {
+ switch ( rEntry.eOp )
+ {
+ case SC_LESS_EQUAL :
+ case SC_GREATER_EQUAL :
+ rEntry.eOp = SC_EQUAL;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ break; // for
+ }
+ SCSIZE nColRowSave;
+ bIgnoreMismatchOnLeadingStrings = FALSE;
+ SetTestEqualCondition( FALSE );
+ do
+ {
+ nFoundCol = GetCol();
+ nFoundRow = GetRow();
+ nColRowSave = nColRow;
+ } while (GetNext());
+ // Step back conditions same as above
+ nCol = nFoundCol;
+ nRow = nFoundRow;
+ nColRow = nColRowSave;
+ return TRUE;
+ }
+ if ( (bSearchForEqualAfterMismatch || aParam.bRegExp) &&
+ StoppedOnMismatch() )
+ {
+ // Assume found entry to be the last value less than respectively
+ // greater than the query. But keep on searching for an equal match.
+ SCSIZE nEntries = aParam.GetEntryCount();
+ for ( SCSIZE j = 0; j < nEntries; j++ )
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry( j );
+ if ( rEntry.bDoQuery )
+ {
+ switch ( rEntry.eOp )
+ {
+ case SC_LESS_EQUAL :
+ case SC_GREATER_EQUAL :
+ rEntry.eOp = SC_EQUAL;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ break; // for
+ }
+ SetStopOnMismatch( FALSE );
+ SetTestEqualCondition( FALSE );
+ if (GetNext())
+ {
+ // Last of a consecutive area, avoid searching the entire parameter
+ // range as it is a real performance bottleneck in case of regular
+ // expressions.
+ SCSIZE nColRowSave;
+ do
+ {
+ nFoundCol = GetCol();
+ nFoundRow = GetRow();
+ nColRowSave = nColRow;
+ SetStopOnMismatch( TRUE );
+ } while (GetNext());
+ nCol = nFoundCol;
+ nRow = nFoundRow;
+ nColRow = nColRowSave;
+ }
+ }
+ return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW);
+}
+
+
+ScBaseCell* ScQueryCellIterator::BinarySearch()
+{
+ nCol = aParam.nCol1;
+ ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
+ if (!pCol->nCount)
+ return 0;
+
+ ScBaseCell* pCell;
+ SCSIZE nHi, nLo;
+ CollatorWrapper* pCollator = (aParam.bCaseSens ? ScGlobal::pCaseCollator :
+ ScGlobal::pCollator);
+ SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable());
+ const ScQueryEntry& rEntry = aParam.GetEntry(0);
+ bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL;
+ bool bByString = rEntry.bQueryByString;
+ bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
+ bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
+ !aParam.bHasHeader && bByString;
+
+ nRow = aParam.nRow1;
+ if (aParam.bHasHeader)
+ nRow++;
+ const ColEntry* pItems = pCol->pItems;
+ if (pCol->Search( nRow, nLo ) && bFirstStringIgnore &&
+ pItems[nLo].pCell->HasStringData())
+ {
+ String aCellStr;
+ ULONG nFormat = pCol->GetNumberFormat( pItems[nLo].nRow);
+ ScCellFormat::GetInputString( pItems[nLo].pCell, nFormat, aCellStr,
+ rFormatter);
+ sal_Int32 nTmp = pCollator->compareString( aCellStr, *rEntry.pStr);
+ if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
+ (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
+ (rEntry.eOp == SC_EQUAL && nTmp != 0))
+ ++nLo;
+ }
+ if (!pCol->Search( aParam.nRow2, nHi ) && nHi>0)
+ --nHi;
+ while (bAllStringIgnore && nLo <= nHi && nLo < pCol->nCount &&
+ pItems[nLo].pCell->HasStringData())
+ ++nLo;
+
+ // Bookkeeping values for breaking up the binary search in case the data
+ // range isn't strictly sorted.
+ SCSIZE nLastInRange = nLo;
+ SCSIZE nFirstLastInRange = nLastInRange;
+ double fLastInRangeValue = bLessEqual ?
+ -(::std::numeric_limits<double>::max()) :
+ ::std::numeric_limits<double>::max();
+ String aLastInRangeString;
+ if (!bLessEqual)
+ aLastInRangeString.Assign( sal_Unicode(0xFFFF));
+ if (nLastInRange < pCol->nCount)
+ {
+ pCell = pItems[nLastInRange].pCell;
+ if (pCell->HasStringData())
+ {
+ ULONG nFormat = pCol->GetNumberFormat( pItems[nLastInRange].nRow);
+ ScCellFormat::GetInputString( pCell, nFormat, aLastInRangeString,
+ rFormatter);
+ }
+ else
+ {
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ fLastInRangeValue =
+ static_cast<ScValueCell*>(pCell)->GetValue();
+ break;
+ case CELLTYPE_FORMULA :
+ fLastInRangeValue =
+ static_cast<ScFormulaCell*>(pCell)->GetValue();
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+
+ sal_Int32 nRes = 0;
+ bool bFound = false;
+ bool bDone = false;
+ while (nLo <= nHi && !bDone)
+ {
+ SCSIZE nMid = (nLo+nHi)/2;
+ SCSIZE i = nMid;
+ while (i <= nHi && pItems[i].pCell->GetCellType() == CELLTYPE_NOTE)
+ ++i;
+ if (i > nHi)
+ {
+ if (nMid > 0)
+ nHi = nMid - 1;
+ else
+ bDone = true;
+ continue; // while
+ }
+ BOOL bStr = pItems[i].pCell->HasStringData();
+ nRes = 0;
+ // compares are content<query:-1, content>query:1
+ // Cell value comparison similar to ScTable::ValidQuery()
+ if (!bStr && !bByString)
+ {
+ double nCellVal;
+ pCell = pItems[i].pCell;
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ nCellVal = static_cast<ScValueCell*>(pCell)->GetValue();
+ break;
+ case CELLTYPE_FORMULA :
+ nCellVal = static_cast<ScFormulaCell*>(pCell)->GetValue();
+ break;
+ default:
+ nCellVal = 0.0;
+ }
+ if ((nCellVal < rEntry.nVal) && !::rtl::math::approxEqual(
+ nCellVal, rEntry.nVal))
+ {
+ nRes = -1;
+ if (bLessEqual)
+ {
+ if (fLastInRangeValue < nCellVal)
+ {
+ fLastInRangeValue = nCellVal;
+ nLastInRange = i;
+ }
+ else if (fLastInRangeValue > nCellVal)
+ {
+ // not strictly sorted, continue with GetThis()
+ nLastInRange = nFirstLastInRange;
+ bDone = true;
+ }
+ }
+ }
+ else if ((nCellVal > rEntry.nVal) && !::rtl::math::approxEqual(
+ nCellVal, rEntry.nVal))
+ {
+ nRes = 1;
+ if (!bLessEqual)
+ {
+ if (fLastInRangeValue > nCellVal)
+ {
+ fLastInRangeValue = nCellVal;
+ nLastInRange = i;
+ }
+ else if (fLastInRangeValue < nCellVal)
+ {
+ // not strictly sorted, continue with GetThis()
+ nLastInRange = nFirstLastInRange;
+ bDone = true;
+ }
+ }
+ }
+ }
+ else if (bStr && bByString)
+ {
+ String aCellStr;
+ ULONG nFormat = pCol->GetNumberFormat( pItems[i].nRow);
+ ScCellFormat::GetInputString( pItems[i].pCell, nFormat, aCellStr,
+ rFormatter);
+ nRes = pCollator->compareString( aCellStr, *rEntry.pStr);
+ if (nRes < 0 && bLessEqual)
+ {
+ sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
+ aCellStr);
+ if (nTmp < 0)
+ {
+ aLastInRangeString = aCellStr;
+ nLastInRange = i;
+ }
+ else if (nTmp > 0)
+ {
+ // not strictly sorted, continue with GetThis()
+ nLastInRange = nFirstLastInRange;
+ bDone = true;
+ }
+ }
+ else if (nRes > 0 && !bLessEqual)
+ {
+ sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
+ aCellStr);
+ if (nTmp > 0)
+ {
+ aLastInRangeString = aCellStr;
+ nLastInRange = i;
+ }
+ else if (nTmp < 0)
+ {
+ // not strictly sorted, continue with GetThis()
+ nLastInRange = nFirstLastInRange;
+ bDone = true;
+ }
+ }
+ }
+ else if (!bStr && bByString)
+ {
+ nRes = -1; // numeric < string
+ if (bLessEqual)
+ nLastInRange = i;
+ }
+ else // if (bStr && !bByString)
+ {
+ nRes = 1; // string > numeric
+ if (!bLessEqual)
+ nLastInRange = i;
+ }
+ if (nRes < 0)
+ {
+ if (bLessEqual)
+ nLo = nMid + 1;
+ else // assumed to be SC_GREATER_EQUAL
+ {
+ if (nMid > 0)
+ nHi = nMid - 1;
+ else
+ bDone = true;
+ }
+ }
+ else if (nRes > 0)
+ {
+ if (bLessEqual)
+ {
+ if (nMid > 0)
+ nHi = nMid - 1;
+ else
+ bDone = true;
+ }
+ else // assumed to be SC_GREATER_EQUAL
+ nLo = nMid + 1;
+ }
+ else
+ {
+ nLo = i;
+ bDone = bFound = true;
+ }
+ }
+ if (!bFound)
+ {
+ // If all hits didn't result in a moving limit there's something
+ // strange, e.g. data range not properly sorted, or only identical
+ // values encountered, which doesn't mean there aren't any others in
+ // between.. leave it to GetThis(). The condition for this would be
+ // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
+ // Else, in case no exact match was found, we step back for a
+ // subsequent GetThis() to find the last in range. Effectively this is
+ // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
+ nLo = nLastInRange;
+ }
+ if (nLo < pCol->nCount && pCol->pItems[nLo].nRow <= aParam.nRow2)
+ {
+ nRow = pItems[nLo].nRow;
+ pCell = pItems[nLo].pCell;
+ nColRow = nLo;
+ }
+ else
+ {
+ nRow = aParam.nRow2 + 1;
+ pCell = 0;
+ nColRow = pCol->nCount - 1;
+ }
+ return pCell;
+}
+
+
+//-------------------------------------------------------------------------------
+
+ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
+ pDoc( pDocument ),
+ nTab( nTable ),
+ nStartCol( nCol1 ),
+ nEndCol( nCol2 ),
+ nEndRow( nRow2 ),
+ nCol( nCol1 ),
+ nRow( nRow1 ),
+ bMore( TRUE )
+{
+ SCCOL i;
+ SCSIZE nIndex;
+
+ pNextRows = new SCROW[ nCol2-nCol1+1 ];
+ pNextIndices = new SCSIZE[ nCol2-nCol1+1 ];
+
+ for (i=nStartCol; i<=nEndCol; i++)
+ {
+ ScColumn* pCol = &pDoc->pTab[nTab]->aCol[i];
+
+ pCol->Search( nRow1, nIndex );
+ if ( nIndex < pCol->nCount )
+ {
+ pNextRows[i-nStartCol] = pCol->pItems[nIndex].nRow;
+ pNextIndices[i-nStartCol] = nIndex;
+ }
+ else
+ {
+ pNextRows[i-nStartCol] = MAXROWCOUNT; // nichts gefunden
+ pNextIndices[i-nStartCol] = MAXROWCOUNT;
+ }
+ }
+
+ if (pNextRows[0] != nRow1)
+ Advance();
+}
+
+ScHorizontalCellIterator::~ScHorizontalCellIterator()
+{
+ delete [] pNextRows;
+ delete [] pNextIndices;
+}
+
+ScBaseCell* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow )
+{
+ if ( bMore )
+ {
+ rCol = nCol;
+ rRow = nRow;
+
+ ScColumn* pCol = &pDoc->pTab[nTab]->aCol[nCol];
+ SCSIZE nIndex = pNextIndices[nCol-nStartCol];
+ DBG_ASSERT( nIndex < pCol->nCount, "ScHorizontalCellIterator::GetNext: nIndex out of range" );
+ ScBaseCell* pCell = pCol->pItems[nIndex].pCell;
+ if ( ++nIndex < pCol->nCount )
+ {
+ pNextRows[nCol-nStartCol] = pCol->pItems[nIndex].nRow;
+ pNextIndices[nCol-nStartCol] = nIndex;
+ }
+ else
+ {
+ pNextRows[nCol-nStartCol] = MAXROWCOUNT; // nichts gefunden
+ pNextIndices[nCol-nStartCol] = MAXROWCOUNT;
+ }
+
+ Advance();
+ return pCell;
+ }
+ else
+ return NULL;
+}
+
+BOOL ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow )
+{
+ rCol = nCol;
+ rRow = nRow;
+ return bMore;
+}
+
+void ScHorizontalCellIterator::Advance()
+{
+ BOOL bFound = FALSE;
+ SCCOL i;
+
+ for (i=nCol+1; i<=nEndCol && !bFound; i++)
+ if (pNextRows[i-nStartCol] == nRow)
+ {
+ nCol = i;
+ bFound = TRUE;
+ }
+
+ if (!bFound)
+ {
+ SCROW nMinRow = MAXROW+1;
+ for (i=nStartCol; i<=nEndCol; i++)
+ if (pNextRows[i-nStartCol] < nMinRow)
+ {
+ nCol = i;
+ nMinRow = pNextRows[i-nStartCol];
+ }
+
+ if (nMinRow <= nEndRow)
+ {
+ nRow = nMinRow;
+ bFound = TRUE;
+ }
+ }
+
+ if ( !bFound )
+ bMore = FALSE;
+}
+
+//-------------------------------------------------------------------------------
+
+ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
+ pDoc( pDocument ),
+ nTab( nTable ),
+ nStartCol( nCol1 ),
+ nStartRow( nRow1 ),
+ nEndCol( nCol2 ),
+ nEndRow( nRow2 )
+{
+ DBG_ASSERT( pDoc->pTab[nTab], "Tabelle nicht da" );
+
+ SCCOL i;
+
+ nRow = nStartRow;
+ nCol = nStartCol;
+ bRowEmpty = FALSE;
+
+ pIndices = new SCSIZE[nEndCol-nStartCol+1];
+ pNextEnd = new SCROW[nEndCol-nStartCol+1];
+ ppPatterns = new const ScPatternAttr*[nEndCol-nStartCol+1];
+
+ SCROW nSkipTo = MAXROW;
+ BOOL bEmpty = TRUE;
+ for (i=nStartCol; i<=nEndCol; i++)
+ {
+ SCCOL nPos = i - nStartCol;
+ ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
+ DBG_ASSERT( pArray, "pArray == 0" );
+
+ SCSIZE nIndex;
+ pArray->Search( nStartRow, nIndex );
+
+ const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
+ SCROW nThisEnd = pArray->pData[nIndex].nRow;
+ if ( IsDefaultItem( pPattern ) )
+ {
+ pPattern = NULL;
+ if ( nThisEnd < nSkipTo )
+ nSkipTo = nThisEnd; // nSkipTo kann gleich hier gesetzt werden
+ }
+ else
+ bEmpty = FALSE; // Attribute gefunden
+
+ pIndices[nPos] = nIndex;
+ pNextEnd[nPos] = nThisEnd;
+ ppPatterns[nPos] = pPattern;
+ }
+
+ if (bEmpty)
+ nRow = nSkipTo; // bis zum naechsten Bereichsende ueberspringen
+ bRowEmpty = bEmpty;
+}
+
+ScHorizontalAttrIterator::~ScHorizontalAttrIterator()
+{
+ delete[] (ScPatternAttr**)ppPatterns;
+ delete[] pNextEnd;
+ delete[] pIndices;
+}
+
+const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow )
+{
+ for (;;)
+ {
+ if (!bRowEmpty)
+ {
+ // in dieser Zeile suchen
+
+ while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] )
+ ++nCol;
+
+ if ( nCol <= nEndCol )
+ {
+ const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
+ rRow = nRow;
+ rCol1 = nCol;
+ while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat )
+ ++nCol;
+ rCol2 = nCol;
+ ++nCol; // hochzaehlen fuer naechsten Aufruf
+ return pPat; // gefunden
+ }
+ }
+
+ // naechste Zeile
+
+ ++nRow;
+ if ( nRow > nEndRow ) // schon am Ende?
+ return NULL; // nichts gefunden
+
+ BOOL bEmpty = TRUE;
+ SCCOL i;
+
+ for ( i = nStartCol; i <= nEndCol; i++)
+ {
+ SCCOL nPos = i-nStartCol;
+ if ( pNextEnd[nPos] < nRow )
+ {
+ ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
+
+ SCSIZE nIndex = ++pIndices[nPos];
+ if ( nIndex < pArray->nCount )
+ {
+ const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
+ SCROW nThisEnd = pArray->pData[nIndex].nRow;
+ if ( IsDefaultItem( pPattern ) )
+ pPattern = NULL;
+ else
+ bEmpty = FALSE; // Attribute gefunden
+
+ pNextEnd[nPos] = nThisEnd;
+ ppPatterns[nPos] = pPattern;
+
+ DBG_ASSERT( pNextEnd[nPos] >= nRow, "Reihenfolge durcheinander" );
+ }
+ else
+ {
+ DBG_ERROR("AttrArray reicht nicht bis MAXROW");
+ pNextEnd[nPos] = MAXROW;
+ ppPatterns[nPos] = NULL;
+ }
+ }
+ else if ( ppPatterns[nPos] )
+ bEmpty = FALSE; // Bereich noch nicht zuende
+ }
+
+ if (bEmpty)
+ {
+ SCCOL nCount = nEndCol-nStartCol+1;
+ SCROW nSkipTo = pNextEnd[0]; // naechstes Bereichsende suchen
+ for (i=1; i<nCount; i++)
+ if ( pNextEnd[i] < nSkipTo )
+ nSkipTo = pNextEnd[i];
+ nRow = nSkipTo; // leere Zeilen ueberspringen
+ }
+ bRowEmpty = bEmpty;
+ nCol = nStartCol; // wieder links anfangen
+ }
+
+// return NULL;
+}
+
+//-------------------------------------------------------------------------------
+
+inline BOOL IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 );
+}
+
+ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
+ aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
+ aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
+ nNextCol( nCol1 ),
+ nNextRow( nRow1 )
+{
+ pCell = aCellIter.GetNext( nCellCol, nCellRow );
+ pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
+}
+
+ScUsedAreaIterator::~ScUsedAreaIterator()
+{
+}
+
+BOOL ScUsedAreaIterator::GetNext()
+{
+ // Iteratoren weiterzaehlen
+
+ if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) )
+ pCell = aCellIter.GetNext( nCellCol, nCellRow );
+
+ while ( pCell && pCell->IsBlank() )
+ pCell = aCellIter.GetNext( nCellCol, nCellRow );
+
+ if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) )
+ pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
+
+ if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol )
+ nAttrCol1 = nNextCol;
+
+ // naechsten Abschnitt heraussuchen
+
+ BOOL bFound = TRUE;
+ BOOL bUseCell = FALSE;
+
+ if ( pCell && pPattern )
+ {
+ if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) ) // vorne nur Attribute ?
+ {
+ pFoundCell = NULL;
+ pFoundPattern = pPattern;
+ nFoundRow = nAttrRow;
+ nFoundStartCol = nAttrCol1;
+ if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 ) // auch Zelle im Bereich ?
+ nFoundEndCol = nCellCol - 1; // nur bis vor der Zelle
+ else
+ nFoundEndCol = nAttrCol2; // alles
+ }
+ else
+ {
+ bUseCell = TRUE;
+ if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol ) // Attribute auf der Zelle ?
+ pFoundPattern = pPattern;
+ else
+ pFoundPattern = NULL;
+ }
+ }
+ else if ( pCell ) // nur Zelle -> direkt uebernehmen
+ {
+ pFoundPattern = NULL;
+ bUseCell = TRUE; // Position von Zelle
+ }
+ else if ( pPattern ) // nur Attribute -> direkt uebernehmen
+ {
+ pFoundCell = NULL;
+ pFoundPattern = pPattern;
+ nFoundRow = nAttrRow;
+ nFoundStartCol = nAttrCol1;
+ nFoundEndCol = nAttrCol2;
+ }
+ else // gar nichts
+ bFound = FALSE;
+
+ if ( bUseCell ) // Position von Zelle
+ {
+ pFoundCell = pCell;
+ nFoundRow = nCellRow;
+ nFoundStartCol = nFoundEndCol = nCellCol;
+ }
+
+ if (bFound)
+ {
+ nNextRow = nFoundRow;
+ nNextCol = nFoundEndCol + 1;
+ }
+
+ return bFound;
+}
+
+//-------------------------------------------------------------------------------
+
+ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable,
+ SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2) :
+ pDoc( pDocument ),
+ nTab( nTable ),
+ nEndCol( nCol2 ),
+ nStartRow( nRow1 ),
+ nEndRow( nRow2 ),
+ nCol( nCol1 )
+{
+ if ( ValidTab(nTab) && pDoc->pTab[nTab] )
+ pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
+ else
+ pColIter = NULL;
+}
+
+ScDocAttrIterator::~ScDocAttrIterator()
+{
+ delete pColIter;
+}
+
+const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 )
+{
+ while ( pColIter )
+ {
+ const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
+ if ( pPattern )
+ {
+ rCol = nCol;
+ return pPattern;
+ }
+
+ delete pColIter;
+ ++nCol;
+ if ( nCol <= nEndCol )
+ pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
+ else
+ pColIter = NULL;
+ }
+ return NULL; // is nix mehr
+}
+
+//-------------------------------------------------------------------------------
+
+ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable,
+ SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2) :
+ pDoc( pDocument ),
+ nTab( nTable ),
+ nEndCol( nCol2 ),
+ nStartRow( nRow1 ),
+ nEndRow( nRow2 ),
+ nIterStartCol( nCol1 ),
+ nIterEndCol( nCol1 )
+{
+ if ( ValidTab(nTab) && pDoc->pTab[nTab] )
+ {
+ pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
+ while ( nIterEndCol < nEndCol &&
+ pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
+ pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
+ ++nIterEndCol;
+ }
+ else
+ pColIter = NULL;
+}
+
+ScAttrRectIterator::~ScAttrRectIterator()
+{
+ delete pColIter;
+}
+
+void ScAttrRectIterator::DataChanged()
+{
+ if (pColIter)
+ {
+ SCROW nNextRow = pColIter->GetNextRow();
+ delete pColIter;
+ pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow );
+ }
+}
+
+const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2,
+ SCROW& rRow1, SCROW& rRow2 )
+{
+ while ( pColIter )
+ {
+ const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
+ if ( pPattern )
+ {
+ rCol1 = nIterStartCol;
+ rCol2 = nIterEndCol;
+ return pPattern;
+ }
+
+ delete pColIter;
+ nIterStartCol = nIterEndCol+1;
+ if ( nIterStartCol <= nEndCol )
+ {
+ nIterEndCol = nIterStartCol;
+ pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
+ while ( nIterEndCol < nEndCol &&
+ pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
+ pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
+ ++nIterEndCol;
+ }
+ else
+ pColIter = NULL;
+ }
+ return NULL; // is nix mehr
+}
+
diff --git a/sc/source/core/data/docpool.cxx b/sc/source/core/data/docpool.cxx
new file mode 100644
index 000000000000..c2a77a0d0ede
--- /dev/null
+++ b/sc/source/core/data/docpool.cxx
@@ -0,0 +1,1042 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: docpool.cxx,v $
+ * $Revision: 1.25.144.1 $
+ *
+ * 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 <tools/shl.hxx>
+#include <vcl/outdev.hxx>
+#include <svtools/aeitem.hxx>
+#include <svtools/itemiter.hxx>
+#include <svx/algitem.hxx>
+#include <svx/boxitem.hxx>
+#include <svx/bolnitem.hxx>
+#include <svx/brshitem.hxx>
+#include <svx/charreliefitem.hxx>
+#include <svx/cntritem.hxx>
+#include <svx/colritem.hxx>
+#include <svx/crsditem.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/emphitem.hxx>
+#include <svx/fhgtitem.hxx>
+#include <svx/fontitem.hxx>
+#include <svx/forbiddenruleitem.hxx>
+#include <svx/frmdiritem.hxx>
+#include <svx/hngpnctitem.hxx>
+#include <svx/itemtype.hxx>
+#include <svx/langitem.hxx>
+#include <svx/lrspitem.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/pbinitem.hxx>
+#include <svx/postitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <svx/scriptspaceitem.hxx>
+#include <svx/shaditem.hxx>
+#include <svx/shdditem.hxx>
+#include <svx/sizeitem.hxx>
+#include <svx/svxitems.hrc>
+#include <svx/udlnitem.hxx>
+#include <svx/ulspitem.hxx>
+#include <svx/wghtitem.hxx>
+#include <svx/wrlmitem.hxx>
+#include <svx/xmlcnitm.hxx>
+
+#include "docpool.hxx"
+#include "global.hxx"
+#include "attrib.hxx"
+#include "patattr.hxx"
+#include "globstr.hrc"
+#include "sc.hrc" // Slot-IDs
+
+
+#define SC_MAX_POOLREF (SFX_ITEMS_OLD_MAXREF - 39)
+#define SC_SAFE_POOLREF (SC_MAX_POOLREF + 20)
+
+// STATIC DATA -----------------------------------------------------------
+
+USHORT* ScDocumentPool::pVersionMap1 = 0;
+USHORT* ScDocumentPool::pVersionMap2 = 0;
+USHORT* ScDocumentPool::pVersionMap3 = 0;
+USHORT* ScDocumentPool::pVersionMap4 = 0;
+USHORT* ScDocumentPool::pVersionMap5 = 0;
+USHORT* ScDocumentPool::pVersionMap6 = 0;
+USHORT* ScDocumentPool::pVersionMap7 = 0;
+USHORT* ScDocumentPool::pVersionMap8 = 0;
+USHORT* ScDocumentPool::pVersionMap9 = 0;
+USHORT* ScDocumentPool::pVersionMap10 = 0;
+USHORT* ScDocumentPool::pVersionMap11 = 0;
+
+// ATTR_FONT_TWOLINES (not used) was changed to ATTR_USERDEF (not saved in binary format) in 641c
+
+static SfxItemInfo __READONLY_DATA aItemInfos[] =
+{
+ { SID_ATTR_CHAR_FONT, SFX_ITEM_POOLABLE }, // ATTR_FONT
+ { SID_ATTR_CHAR_FONTHEIGHT, SFX_ITEM_POOLABLE }, // ATTR_FONT_HEIGHT
+ { SID_ATTR_CHAR_WEIGHT, SFX_ITEM_POOLABLE }, // ATTR_FONT_WEIGHT
+ { SID_ATTR_CHAR_POSTURE, SFX_ITEM_POOLABLE }, // ATTR_FONT_POSTURE
+ { SID_ATTR_CHAR_UNDERLINE, SFX_ITEM_POOLABLE }, // ATTR_FONT_UNDERLINE
+ { SID_ATTR_CHAR_OVERLINE, SFX_ITEM_POOLABLE }, // ATTR_FONT_OVERLINE
+ { SID_ATTR_CHAR_STRIKEOUT, SFX_ITEM_POOLABLE }, // ATTR_FONT_CROSSEDOUT
+ { SID_ATTR_CHAR_CONTOUR, SFX_ITEM_POOLABLE }, // ATTR_FONT_CONTOUR
+ { SID_ATTR_CHAR_SHADOWED, SFX_ITEM_POOLABLE }, // ATTR_FONT_SHADOWED
+ { SID_ATTR_CHAR_COLOR, SFX_ITEM_POOLABLE }, // ATTR_FONT_COLOR
+ { SID_ATTR_CHAR_LANGUAGE, SFX_ITEM_POOLABLE }, // ATTR_FONT_LANGUAGE
+ { SID_ATTR_CHAR_CJK_FONT, SFX_ITEM_POOLABLE }, // ATTR_CJK_FONT from 614
+ { SID_ATTR_CHAR_CJK_FONTHEIGHT, SFX_ITEM_POOLABLE }, // ATTR_CJK_FONT_HEIGHT from 614
+ { SID_ATTR_CHAR_CJK_WEIGHT, SFX_ITEM_POOLABLE }, // ATTR_CJK_FONT_WEIGHT from 614
+ { SID_ATTR_CHAR_CJK_POSTURE, SFX_ITEM_POOLABLE }, // ATTR_CJK_FONT_POSTURE from 614
+ { SID_ATTR_CHAR_CJK_LANGUAGE, SFX_ITEM_POOLABLE }, // ATTR_CJK_FONT_LANGUAGE from 614
+ { SID_ATTR_CHAR_CTL_FONT, SFX_ITEM_POOLABLE }, // ATTR_CTL_FONT from 614
+ { SID_ATTR_CHAR_CTL_FONTHEIGHT, SFX_ITEM_POOLABLE }, // ATTR_CTL_FONT_HEIGHT from 614
+ { SID_ATTR_CHAR_CTL_WEIGHT, SFX_ITEM_POOLABLE }, // ATTR_CTL_FONT_WEIGHT from 614
+ { SID_ATTR_CHAR_CTL_POSTURE, SFX_ITEM_POOLABLE }, // ATTR_CTL_FONT_POSTURE from 614
+ { SID_ATTR_CHAR_CTL_LANGUAGE, SFX_ITEM_POOLABLE }, // ATTR_CTL_FONT_LANGUAGE from 614
+ { SID_ATTR_CHAR_EMPHASISMARK, SFX_ITEM_POOLABLE }, // ATTR_FONT_EMPHASISMARK from 614
+ { 0, SFX_ITEM_POOLABLE }, // ATTR_USERDEF from 614 / 641c
+ { SID_ATTR_CHAR_WORDLINEMODE, SFX_ITEM_POOLABLE }, // ATTR_FONT_WORDLINE from 632b
+ { SID_ATTR_CHAR_RELIEF, SFX_ITEM_POOLABLE }, // ATTR_FONT_RELIEF from 632b
+ { SID_ATTR_ALIGN_HYPHENATION, SFX_ITEM_POOLABLE }, // ATTR_HYPHENATE from 632b
+ { 0, SFX_ITEM_POOLABLE }, // ATTR_SCRIPTSPACE from 614d
+ { 0, SFX_ITEM_POOLABLE }, // ATTR_HANGPUNCTUATION from 614d
+ { SID_ATTR_PARA_FORBIDDEN_RULES,SFX_ITEM_POOLABLE }, // ATTR_FORBIDDEN_RULES from 614d
+ { SID_ATTR_ALIGN_HOR_JUSTIFY, SFX_ITEM_POOLABLE }, // ATTR_HOR_JUSTIFY
+ { SID_ATTR_ALIGN_INDENT, SFX_ITEM_POOLABLE }, // ATTR_INDENT ab 350
+ { SID_ATTR_ALIGN_VER_JUSTIFY, SFX_ITEM_POOLABLE }, // ATTR_VER_JUSTIFY
+ { SID_ATTR_ALIGN_STACKED, SFX_ITEM_POOLABLE }, // ATTR_STACKED from 680/dr14 (replaces ATTR_ORIENTATION)
+ { SID_ATTR_ALIGN_DEGREES, SFX_ITEM_POOLABLE }, // ATTR_ROTATE_VALUE ab 367
+ { SID_ATTR_ALIGN_LOCKPOS, SFX_ITEM_POOLABLE }, // ATTR_ROTATE_MODE ab 367
+ { SID_ATTR_ALIGN_ASIANVERTICAL, SFX_ITEM_POOLABLE }, // ATTR_VERTICAL_ASIAN from 642
+ { SID_ATTR_FRAMEDIRECTION, SFX_ITEM_POOLABLE }, // ATTR_WRITINGDIR from 643
+ { SID_ATTR_ALIGN_LINEBREAK, SFX_ITEM_POOLABLE }, // ATTR_LINEBREAK
+ { SID_ATTR_ALIGN_SHRINKTOFIT, SFX_ITEM_POOLABLE }, // ATTR_SHRINKTOFIT from 680/dr14
+ { SID_ATTR_BORDER_DIAG_TLBR, SFX_ITEM_POOLABLE }, // ATTR_BORDER_TLBR from 680/dr14
+ { SID_ATTR_BORDER_DIAG_BLTR, SFX_ITEM_POOLABLE }, // ATTR_BORDER_BLTR from 680/dr14
+ { SID_ATTR_ALIGN_MARGIN, SFX_ITEM_POOLABLE }, // ATTR_MARGIN
+ { 0, SFX_ITEM_POOLABLE }, // ATTR_MERGE
+ { 0, SFX_ITEM_POOLABLE }, // ATTR_MERGE_FLAG
+ { SID_ATTR_NUMBERFORMAT_VALUE, SFX_ITEM_POOLABLE }, // ATTR_VALUE_FORMAT
+ { ATTR_LANGUAGE_FORMAT, SFX_ITEM_POOLABLE }, // ATTR_LANGUAGE_FORMAT ab 329, wird im Dialog mit SID_ATTR_NUMBERFORMAT_VALUE kombiniert
+ { SID_ATTR_BRUSH, SFX_ITEM_POOLABLE }, // ATTR_BACKGROUND
+ { SID_SCATTR_PROTECTION, SFX_ITEM_POOLABLE }, // ATTR_PROTECTION
+ { SID_ATTR_BORDER_OUTER, SFX_ITEM_POOLABLE }, // ATTR_BORDER
+ { SID_ATTR_BORDER_INNER, SFX_ITEM_POOLABLE }, // ATTR_BORDER_INNER
+ { SID_ATTR_BORDER_SHADOW, SFX_ITEM_POOLABLE }, // ATTR_SHADOW
+ { 0, SFX_ITEM_POOLABLE }, // ATTR_VALIDDATA
+ { 0, SFX_ITEM_POOLABLE }, // ATTR_CONDITIONAL
+ { 0, SFX_ITEM_POOLABLE }, // ATTR_PATTERN
+ { SID_ATTR_LRSPACE, SFX_ITEM_POOLABLE }, // ATTR_LRSPACE
+ { SID_ATTR_ULSPACE, SFX_ITEM_POOLABLE }, // ATTR_ULSPACE
+ { SID_ATTR_PAGE, SFX_ITEM_POOLABLE }, // ATTR_PAGE
+ { 0, SFX_ITEM_POOLABLE }, // ATTR_PAGE_PAPERTRAY, seit 303 nur noch dummy
+ { SID_ATTR_PAGE_PAPERBIN, SFX_ITEM_POOLABLE }, // ATTR_PAGE_PAPERBIN
+ { SID_ATTR_PAGE_SIZE, SFX_ITEM_POOLABLE }, // ATTR_PAGE_SIZE
+ { SID_ATTR_PAGE_MAXSIZE, SFX_ITEM_POOLABLE }, // ATTR_PAGE_MAXSIZE
+ { SID_ATTR_PAGE_EXT1, SFX_ITEM_POOLABLE }, // ATTR_PAGE_HORCENTER
+ { SID_ATTR_PAGE_EXT2, SFX_ITEM_POOLABLE }, // ATTR_PAGE_VERCENTER
+ { SID_ATTR_PAGE_ON, SFX_ITEM_POOLABLE }, // ATTR_PAGE_ON
+ { SID_ATTR_PAGE_DYNAMIC, SFX_ITEM_POOLABLE }, // ATTR_PAGE_DYNAMIC
+ { SID_ATTR_PAGE_SHARED, SFX_ITEM_POOLABLE }, // ATTR_PAGE_SHARED
+ { SID_SCATTR_PAGE_NOTES, SFX_ITEM_POOLABLE }, // ATTR_PAGE_NOTES
+ { SID_SCATTR_PAGE_GRID, SFX_ITEM_POOLABLE }, // ATTR_PAGE_GRID
+ { SID_SCATTR_PAGE_HEADERS, SFX_ITEM_POOLABLE }, // ATTR_PAGE_HEADERS
+ { SID_SCATTR_PAGE_CHARTS, SFX_ITEM_POOLABLE }, // ATTR_PAGE_CHARTS
+ { SID_SCATTR_PAGE_OBJECTS, SFX_ITEM_POOLABLE }, // ATTR_PAGE_OBJECTS
+ { SID_SCATTR_PAGE_DRAWINGS, SFX_ITEM_POOLABLE }, // ATTR_PAGE_DRAWINGS
+ { SID_SCATTR_PAGE_TOPDOWN, SFX_ITEM_POOLABLE }, // ATTR_PAGE_TOPDOWN
+ { SID_SCATTR_PAGE_SCALE, SFX_ITEM_POOLABLE }, // ATTR_PAGE_SCALE
+ { SID_SCATTR_PAGE_SCALETOPAGES, SFX_ITEM_POOLABLE }, // ATTR_PAGE_SCALETOPAGES
+ { SID_SCATTR_PAGE_FIRSTPAGENO, SFX_ITEM_POOLABLE }, // ATTR_PAGE_FIRSTPAGENO
+ { SID_SCATTR_PAGE_PRINTAREA, SFX_ITEM_POOLABLE }, // ATTR_PAGE_PRINTAREA
+ { SID_SCATTR_PAGE_REPEATROW, SFX_ITEM_POOLABLE }, // ATTR_PAGE_REPEATROW
+ { SID_SCATTR_PAGE_REPEATCOL, SFX_ITEM_POOLABLE }, // ATTR_PAGE_REPEATCOL
+ { SID_SCATTR_PAGE_PRINTTABLES, SFX_ITEM_POOLABLE }, // ATTR_PAGE_PRINTTABLES
+ { SID_SCATTR_PAGE_HEADERLEFT, SFX_ITEM_POOLABLE }, // ATTR_PAGE_HEADERLEFT
+ { SID_SCATTR_PAGE_FOOTERLEFT, SFX_ITEM_POOLABLE }, // ATTR_PAGE_FOOTERLEFT
+ { SID_SCATTR_PAGE_HEADERRIGHT, SFX_ITEM_POOLABLE }, // ATTR_PAGE_HEADERRIGHT
+ { SID_SCATTR_PAGE_FOOTERRIGHT, SFX_ITEM_POOLABLE }, // ATTR_PAGE_FOOTERRIGHT
+ { SID_ATTR_PAGE_HEADERSET, SFX_ITEM_POOLABLE }, // ATTR_PAGE_HEADERSET
+ { SID_ATTR_PAGE_FOOTERSET, SFX_ITEM_POOLABLE }, // ATTR_PAGE_FOOTERSET
+ { SID_SCATTR_PAGE_FORMULAS, SFX_ITEM_POOLABLE }, // ATTR_PAGE_FORMULAS
+ { SID_SCATTR_PAGE_NULLVALS, SFX_ITEM_POOLABLE }, // ATTR_PAGE_NULLVALS
+ { SID_SCATTR_PAGE_SCALETO, SFX_ITEM_POOLABLE } // ATTR_PAGE_SCALETO
+};
+
+// -----------------------------------------------------------------------
+
+ScDocumentPool::ScDocumentPool( SfxItemPool* pSecPool, BOOL bLoadRefCounts )
+
+ : SfxItemPool ( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("ScDocumentPool")),
+ ATTR_STARTINDEX, ATTR_ENDINDEX,
+ aItemInfos, NULL, bLoadRefCounts ),
+ pSecondary ( pSecPool )
+{
+ // latin font from GetDefaultFonts is not used, DEFAULTFONT_LATIN_SPREADSHEET instead
+ Font aStdFont = OutputDevice::GetDefaultFont( DEFAULTFONT_LATIN_SPREADSHEET, LANGUAGE_ENGLISH_US,
+ DEFAULTFONT_FLAGS_ONLYONE );
+ SvxFontItem* pStdFont = new SvxFontItem( aStdFont.GetFamily(),
+ aStdFont.GetName(), aStdFont.GetStyleName(),
+ aStdFont.GetPitch(), aStdFont.GetCharSet(),
+ ATTR_FONT );
+
+ SvxFontItem* pCjkFont = new SvxFontItem( ATTR_CJK_FONT );
+ SvxFontItem* pCtlFont = new SvxFontItem( ATTR_CTL_FONT );
+ SvxFontItem aDummy( ATTR_FONT );
+ GetDefaultFonts( aDummy, *pCjkFont, *pCtlFont );
+
+ SvxBoxInfoItem* pGlobalBorderInnerAttr = new SvxBoxInfoItem( ATTR_BORDER_INNER );
+ SfxItemSet* pSet = new SfxItemSet( *this, ATTR_PATTERN_START, ATTR_PATTERN_END );
+ SfxItemSet aSetItemItemSet( *this,
+ ATTR_BACKGROUND, ATTR_BACKGROUND,
+ ATTR_BORDER, ATTR_SHADOW,
+ ATTR_LRSPACE, ATTR_ULSPACE,
+ ATTR_PAGE_SIZE, ATTR_PAGE_SIZE,
+ ATTR_PAGE_ON, ATTR_PAGE_SHARED,
+ 0 );
+
+ pGlobalBorderInnerAttr->SetLine(NULL, BOXINFO_LINE_HORI);
+ pGlobalBorderInnerAttr->SetLine(NULL, BOXINFO_LINE_VERT);
+ pGlobalBorderInnerAttr->SetTable(TRUE);
+ pGlobalBorderInnerAttr->SetDist(TRUE);
+ pGlobalBorderInnerAttr->SetMinDist(FALSE);
+
+ ppPoolDefaults = new SfxPoolItem*[ATTR_ENDINDEX-ATTR_STARTINDEX+1];
+
+ ppPoolDefaults[ ATTR_FONT - ATTR_STARTINDEX ] = pStdFont;
+ ppPoolDefaults[ ATTR_FONT_HEIGHT - ATTR_STARTINDEX ] = new SvxFontHeightItem( 200, 100, ATTR_FONT_HEIGHT ); // 10 pt;
+ ppPoolDefaults[ ATTR_FONT_WEIGHT - ATTR_STARTINDEX ] = new SvxWeightItem( WEIGHT_NORMAL, ATTR_FONT_WEIGHT );
+ ppPoolDefaults[ ATTR_FONT_POSTURE - ATTR_STARTINDEX ] = new SvxPostureItem( ITALIC_NONE, ATTR_FONT_POSTURE );
+ ppPoolDefaults[ ATTR_FONT_UNDERLINE - ATTR_STARTINDEX ] = new SvxUnderlineItem( UNDERLINE_NONE, ATTR_FONT_UNDERLINE );
+ ppPoolDefaults[ ATTR_FONT_OVERLINE - ATTR_STARTINDEX ] = new SvxOverlineItem( UNDERLINE_NONE, ATTR_FONT_OVERLINE );
+ ppPoolDefaults[ ATTR_FONT_CROSSEDOUT - ATTR_STARTINDEX ] = new SvxCrossedOutItem( STRIKEOUT_NONE, ATTR_FONT_CROSSEDOUT );
+ ppPoolDefaults[ ATTR_FONT_CONTOUR - ATTR_STARTINDEX ] = new SvxContourItem( sal_False, ATTR_FONT_CONTOUR );
+ ppPoolDefaults[ ATTR_FONT_SHADOWED - ATTR_STARTINDEX ] = new SvxShadowedItem( sal_False, ATTR_FONT_SHADOWED );
+ ppPoolDefaults[ ATTR_FONT_COLOR - ATTR_STARTINDEX ] = new SvxColorItem( Color(COL_AUTO), ATTR_FONT_COLOR );
+ ppPoolDefaults[ ATTR_FONT_LANGUAGE - ATTR_STARTINDEX ] = new SvxLanguageItem( LanguageType(LANGUAGE_DONTKNOW), ATTR_FONT_LANGUAGE );
+ ppPoolDefaults[ ATTR_CJK_FONT - ATTR_STARTINDEX ] = pCjkFont;
+ ppPoolDefaults[ ATTR_CJK_FONT_HEIGHT - ATTR_STARTINDEX ] = new SvxFontHeightItem( 200, 100, ATTR_CJK_FONT_HEIGHT );
+ ppPoolDefaults[ ATTR_CJK_FONT_WEIGHT - ATTR_STARTINDEX ] = new SvxWeightItem( WEIGHT_NORMAL, ATTR_CJK_FONT_WEIGHT );
+ ppPoolDefaults[ ATTR_CJK_FONT_POSTURE- ATTR_STARTINDEX ] = new SvxPostureItem( ITALIC_NONE, ATTR_CJK_FONT_POSTURE );
+ ppPoolDefaults[ ATTR_CJK_FONT_LANGUAGE-ATTR_STARTINDEX ] = new SvxLanguageItem( LanguageType(LANGUAGE_DONTKNOW),
+ ATTR_CJK_FONT_LANGUAGE );
+ ppPoolDefaults[ ATTR_CTL_FONT - ATTR_STARTINDEX ] = pCtlFont;
+ ppPoolDefaults[ ATTR_CTL_FONT_HEIGHT - ATTR_STARTINDEX ] = new SvxFontHeightItem( 200, 100, ATTR_CTL_FONT_HEIGHT );
+ ppPoolDefaults[ ATTR_CTL_FONT_WEIGHT - ATTR_STARTINDEX ] = new SvxWeightItem( WEIGHT_NORMAL, ATTR_CTL_FONT_WEIGHT );
+ ppPoolDefaults[ ATTR_CTL_FONT_POSTURE- ATTR_STARTINDEX ] = new SvxPostureItem( ITALIC_NONE, ATTR_CTL_FONT_POSTURE );
+ ppPoolDefaults[ ATTR_CTL_FONT_LANGUAGE-ATTR_STARTINDEX ] = new SvxLanguageItem( LanguageType(LANGUAGE_DONTKNOW),
+ ATTR_CTL_FONT_LANGUAGE );
+ ppPoolDefaults[ ATTR_FONT_EMPHASISMARK-ATTR_STARTINDEX ] = new SvxEmphasisMarkItem( EMPHASISMARK_NONE, ATTR_FONT_EMPHASISMARK );
+ ppPoolDefaults[ ATTR_USERDEF - ATTR_STARTINDEX ] = new SvXMLAttrContainerItem( ATTR_USERDEF );
+ ppPoolDefaults[ ATTR_FONT_WORDLINE - ATTR_STARTINDEX ] = new SvxWordLineModeItem(sal_False, ATTR_FONT_WORDLINE );
+ ppPoolDefaults[ ATTR_FONT_RELIEF - ATTR_STARTINDEX ] = new SvxCharReliefItem( RELIEF_NONE, ATTR_FONT_RELIEF );
+ ppPoolDefaults[ ATTR_HYPHENATE - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_HYPHENATE );
+ ppPoolDefaults[ ATTR_SCRIPTSPACE - ATTR_STARTINDEX ] = new SvxScriptSpaceItem( sal_False, ATTR_SCRIPTSPACE);
+ ppPoolDefaults[ ATTR_HANGPUNCTUATION - ATTR_STARTINDEX ] = new SvxHangingPunctuationItem( sal_False, ATTR_HANGPUNCTUATION);
+ ppPoolDefaults[ ATTR_FORBIDDEN_RULES - ATTR_STARTINDEX ] = new SvxForbiddenRuleItem( sal_False, ATTR_FORBIDDEN_RULES);
+ ppPoolDefaults[ ATTR_HOR_JUSTIFY - ATTR_STARTINDEX ] = new SvxHorJustifyItem( SVX_HOR_JUSTIFY_STANDARD, ATTR_HOR_JUSTIFY);
+ ppPoolDefaults[ ATTR_INDENT - ATTR_STARTINDEX ] = new SfxUInt16Item( ATTR_INDENT, 0 );
+ ppPoolDefaults[ ATTR_VER_JUSTIFY - ATTR_STARTINDEX ] = new SvxVerJustifyItem( SVX_VER_JUSTIFY_STANDARD, ATTR_VER_JUSTIFY);
+ ppPoolDefaults[ ATTR_STACKED - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_STACKED, FALSE );
+ ppPoolDefaults[ ATTR_ROTATE_VALUE - ATTR_STARTINDEX ] = new SfxInt32Item( ATTR_ROTATE_VALUE, 0 );
+ ppPoolDefaults[ ATTR_ROTATE_MODE - ATTR_STARTINDEX ] = new SvxRotateModeItem( SVX_ROTATE_MODE_BOTTOM, ATTR_ROTATE_MODE );
+ ppPoolDefaults[ ATTR_VERTICAL_ASIAN - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_VERTICAL_ASIAN );
+ // The default for the ATTR_WRITINGDIR cell attribute must by FRMDIR_ENVIRONMENT,
+ // so that value is returned when asking for a default cell's attributes.
+ // The value from the page style is set as DefaultHorizontalTextDirection for the EditEngine.
+ ppPoolDefaults[ ATTR_WRITINGDIR - ATTR_STARTINDEX ] = new SvxFrameDirectionItem( FRMDIR_ENVIRONMENT, ATTR_WRITINGDIR );
+ ppPoolDefaults[ ATTR_LINEBREAK - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_LINEBREAK );
+ ppPoolDefaults[ ATTR_SHRINKTOFIT - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_SHRINKTOFIT );
+ ppPoolDefaults[ ATTR_BORDER_TLBR - ATTR_STARTINDEX ] = new SvxLineItem( ATTR_BORDER_TLBR );
+ ppPoolDefaults[ ATTR_BORDER_BLTR - ATTR_STARTINDEX ] = new SvxLineItem( ATTR_BORDER_BLTR );
+ ppPoolDefaults[ ATTR_MARGIN - ATTR_STARTINDEX ] = new SvxMarginItem( ATTR_MARGIN );
+ ppPoolDefaults[ ATTR_MERGE - ATTR_STARTINDEX ] = new ScMergeAttr;
+ ppPoolDefaults[ ATTR_MERGE_FLAG - ATTR_STARTINDEX ] = new ScMergeFlagAttr;
+ ppPoolDefaults[ ATTR_VALUE_FORMAT - ATTR_STARTINDEX ] = new SfxUInt32Item( ATTR_VALUE_FORMAT, 0 );
+ ppPoolDefaults[ ATTR_LANGUAGE_FORMAT - ATTR_STARTINDEX ] = new SvxLanguageItem( ScGlobal::eLnge, ATTR_LANGUAGE_FORMAT );
+ ppPoolDefaults[ ATTR_BACKGROUND - ATTR_STARTINDEX ] = new SvxBrushItem( Color(COL_TRANSPARENT), ATTR_BACKGROUND );
+ ppPoolDefaults[ ATTR_PROTECTION - ATTR_STARTINDEX ] = new ScProtectionAttr;
+ ppPoolDefaults[ ATTR_BORDER - ATTR_STARTINDEX ] = new SvxBoxItem( ATTR_BORDER );
+ ppPoolDefaults[ ATTR_BORDER_INNER - ATTR_STARTINDEX ] = pGlobalBorderInnerAttr;
+ ppPoolDefaults[ ATTR_SHADOW - ATTR_STARTINDEX ] = new SvxShadowItem( ATTR_SHADOW );
+ ppPoolDefaults[ ATTR_VALIDDATA - ATTR_STARTINDEX ] = new SfxUInt32Item( ATTR_VALIDDATA, 0 );
+ ppPoolDefaults[ ATTR_CONDITIONAL - ATTR_STARTINDEX ] = new SfxUInt32Item( ATTR_CONDITIONAL, 0 );
+
+ // GetRscString funktioniert erst nach ScGlobal::Init, zu erkennen am EmptyBrushItem
+ //! zusaetzliche Methode ScGlobal::IsInit() oder so...
+ //! oder erkennen, ob dies der Secondary-Pool fuer einen MessagePool ist
+ if ( ScGlobal::GetEmptyBrushItem() )
+ ppPoolDefaults[ ATTR_PATTERN - ATTR_STARTINDEX ] = new ScPatternAttr( pSet, ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
+ else
+ ppPoolDefaults[ ATTR_PATTERN - ATTR_STARTINDEX ] = new ScPatternAttr( pSet,
+ String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM(STRING_STANDARD)) ); //! without name?
+
+ ppPoolDefaults[ ATTR_LRSPACE - ATTR_STARTINDEX ] = new SvxLRSpaceItem( ATTR_LRSPACE );
+ ppPoolDefaults[ ATTR_ULSPACE - ATTR_STARTINDEX ] = new SvxULSpaceItem( ATTR_ULSPACE );
+ ppPoolDefaults[ ATTR_PAGE - ATTR_STARTINDEX ] = new SvxPageItem( ATTR_PAGE );
+ ppPoolDefaults[ ATTR_PAGE_PAPERTRAY - ATTR_STARTINDEX ] = new SfxAllEnumItem( ATTR_PAGE_PAPERTRAY );
+ ppPoolDefaults[ ATTR_PAGE_PAPERBIN - ATTR_STARTINDEX ] = new SvxPaperBinItem( ATTR_PAGE_PAPERBIN );
+ ppPoolDefaults[ ATTR_PAGE_SIZE - ATTR_STARTINDEX ] = new SvxSizeItem( ATTR_PAGE_SIZE );
+ ppPoolDefaults[ ATTR_PAGE_MAXSIZE - ATTR_STARTINDEX ] = new SvxSizeItem( ATTR_PAGE_MAXSIZE );
+ ppPoolDefaults[ ATTR_PAGE_HORCENTER - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_HORCENTER );
+ ppPoolDefaults[ ATTR_PAGE_VERCENTER - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_VERCENTER );
+ ppPoolDefaults[ ATTR_PAGE_ON - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_ON, TRUE );
+ ppPoolDefaults[ ATTR_PAGE_DYNAMIC - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_DYNAMIC, TRUE );
+ ppPoolDefaults[ ATTR_PAGE_SHARED - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_SHARED, TRUE );
+ ppPoolDefaults[ ATTR_PAGE_NOTES - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_NOTES, FALSE );
+ ppPoolDefaults[ ATTR_PAGE_GRID - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_GRID, FALSE );
+ ppPoolDefaults[ ATTR_PAGE_HEADERS - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_HEADERS, FALSE );
+ ppPoolDefaults[ ATTR_PAGE_CHARTS - ATTR_STARTINDEX ] = new ScViewObjectModeItem( ATTR_PAGE_CHARTS );
+ ppPoolDefaults[ ATTR_PAGE_OBJECTS - ATTR_STARTINDEX ] = new ScViewObjectModeItem( ATTR_PAGE_OBJECTS );
+ ppPoolDefaults[ ATTR_PAGE_DRAWINGS - ATTR_STARTINDEX ] = new ScViewObjectModeItem( ATTR_PAGE_DRAWINGS );
+ ppPoolDefaults[ ATTR_PAGE_TOPDOWN - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_TOPDOWN, TRUE );
+ ppPoolDefaults[ ATTR_PAGE_SCALE - ATTR_STARTINDEX ] = new SfxUInt16Item( ATTR_PAGE_SCALE, 100 );
+ ppPoolDefaults[ ATTR_PAGE_SCALETOPAGES-ATTR_STARTINDEX ] = new SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, 1 );
+ ppPoolDefaults[ ATTR_PAGE_FIRSTPAGENO- ATTR_STARTINDEX ] = new SfxUInt16Item( ATTR_PAGE_FIRSTPAGENO, 1 );
+ ppPoolDefaults[ ATTR_PAGE_PRINTAREA - ATTR_STARTINDEX ] = new ScRangeItem( ATTR_PAGE_PRINTAREA );
+ ppPoolDefaults[ ATTR_PAGE_REPEATROW - ATTR_STARTINDEX ] = new ScRangeItem( ATTR_PAGE_REPEATROW );
+ ppPoolDefaults[ ATTR_PAGE_REPEATCOL - ATTR_STARTINDEX ] = new ScRangeItem( ATTR_PAGE_REPEATCOL );
+ ppPoolDefaults[ ATTR_PAGE_PRINTTABLES- ATTR_STARTINDEX ] = new ScTableListItem( ATTR_PAGE_PRINTTABLES );
+ ppPoolDefaults[ ATTR_PAGE_HEADERLEFT - ATTR_STARTINDEX ] = new ScPageHFItem( ATTR_PAGE_HEADERLEFT );
+ ppPoolDefaults[ ATTR_PAGE_FOOTERLEFT - ATTR_STARTINDEX ] = new ScPageHFItem( ATTR_PAGE_FOOTERLEFT );
+ ppPoolDefaults[ ATTR_PAGE_HEADERRIGHT- ATTR_STARTINDEX ] = new ScPageHFItem( ATTR_PAGE_HEADERRIGHT );
+ ppPoolDefaults[ ATTR_PAGE_FOOTERRIGHT- ATTR_STARTINDEX ] = new ScPageHFItem( ATTR_PAGE_FOOTERRIGHT );
+ ppPoolDefaults[ ATTR_PAGE_HEADERSET - ATTR_STARTINDEX ] = new SvxSetItem( ATTR_PAGE_HEADERSET, aSetItemItemSet );
+ ppPoolDefaults[ ATTR_PAGE_FOOTERSET - ATTR_STARTINDEX ] = new SvxSetItem( ATTR_PAGE_FOOTERSET, aSetItemItemSet );
+ ppPoolDefaults[ ATTR_PAGE_FORMULAS - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_FORMULAS, FALSE );
+ ppPoolDefaults[ ATTR_PAGE_NULLVALS - ATTR_STARTINDEX ] = new SfxBoolItem( ATTR_PAGE_NULLVALS, TRUE );
+ ppPoolDefaults[ ATTR_PAGE_SCALETO - ATTR_STARTINDEX ] = new ScPageScaleToItem( 1, 1 );
+// ppPoolDefaults[ ATTR_ITEM_DOUBLE - ATTR_STARTINDEX ] = new ScDoubleItem( ATTR_ITEM_DOUBLE, 0 );
+
+ SetDefaults( ppPoolDefaults );
+
+ if ( pSecondary )
+ SetSecondaryPool( pSecondary );
+
+ // ATTR_LANGUAGE_FORMAT ab sv329 eingefuegt, VersionMap in _ScGlobal__Init
+ SetVersionMap( 1, 100, 157, pVersionMap1 );
+
+ // ATTR_VALIDDATA, ATTR_CONDITIONAL ab 341
+ SetVersionMap( 2, 100, 158, pVersionMap2 );
+
+ // ATTR_INDENT ab 350
+ SetVersionMap( 3, 100, 160, pVersionMap3 );
+
+ // ATTR_ROTATE_VALUE, ATTR_ROTATE_MODE ab 367
+ SetVersionMap( 4, 100, 161, pVersionMap4 );
+
+ // CJK, CTL, EMPHASISMARK, TWOLINES from 614
+ SetVersionMap( 5, 100, 163, pVersionMap5 );
+
+ // ATTR_SCRIPTSPACE, ATTR_HANGPUNCTUATION, ATTR_FORBIDDEN_RULES from 614d
+ SetVersionMap( 6, 100, 175, pVersionMap6 );
+
+ // ATTR_FONT_WORDLINE, ATTR_FONT_RELIEF, ATTR_HYPHENATE from 632b
+ SetVersionMap( 7, 100, 178, pVersionMap7 );
+
+ // ATTR_VERTICAL_ASIAN from 642q
+ SetVersionMap( 8, 100, 181, pVersionMap8 );
+
+ // ATTR_WRITINGDIR from 643y
+ SetVersionMap( 9, 100, 182, pVersionMap9 );
+
+ // ATTR_PAGE_SCALETO added in 680/sab008
+ // new version map not required
+
+ // ATTR_SHRINKTOFIT, ATTR_BORDER_TL_BR, ATTR_BORDER_BL_TR added in 680/dr14
+ SetVersionMap( 10, 100, 184, pVersionMap10 );
+
+ // ATTR_FONT_OVERLINE added in DEV300/overline2
+ SetVersionMap( 11, 100, 187, pVersionMap11 );
+}
+
+__EXPORT ScDocumentPool::~ScDocumentPool()
+{
+ Delete();
+
+ for ( USHORT i=0; i < ATTR_ENDINDEX-ATTR_STARTINDEX+1; i++ )
+ {
+ SetRefCount( *ppPoolDefaults[i], 0 );
+ delete ppPoolDefaults[i];
+ }
+
+ delete[] ppPoolDefaults;
+ SfxItemPool::Free(pSecondary);
+}
+
+void ScDocumentPool::InitVersionMaps()
+{
+ DBG_ASSERT( !pVersionMap1 && !pVersionMap2 &&
+ !pVersionMap3 && !pVersionMap4 &&
+ !pVersionMap5 && !pVersionMap6 &&
+ !pVersionMap7 && !pVersionMap8 &&
+ !pVersionMap9 && !pVersionMap10 &&
+ !pVersionMap11, "InitVersionMaps call multiple times" );
+
+ // alte WhichId's mappen
+ // nicht mit ATTR_* zaehlen, falls die sich nochmal aendern
+
+ // erste Map: ATTR_LANGUAGE_FORMAT ab sv329 eingefuegt
+
+ const USHORT nMap1Start = 100; // alter ATTR_STARTINDEX
+ const USHORT nMap1End = 157; // alter ATTR_ENDINDEX
+ const USHORT nMap1Count = nMap1End - nMap1Start + 1;
+ const USHORT nMap1New = 18; // ATTR_LANGUAGE_FORMAT - ATTR_STARTINDEX
+ pVersionMap1 = new USHORT [ nMap1Count ];
+ USHORT i, j;
+ for ( i=0, j=nMap1Start; i < nMap1New; i++, j++ )
+ pVersionMap1[i] = j;
+ // ein Eintrag eingefuegt...
+ for ( i=nMap1New, j=nMap1Start+nMap1New+1; i < nMap1Count; i++, j++ )
+ pVersionMap1[i] = j;
+
+ // zweite Map: ATTR_VALIDDATA und ATTR_CONDITIONAL ab 341 eingefuegt
+
+ const USHORT nMap2Start = 100; // ATTR_STARTINDEX
+ const USHORT nMap2End = 158; // ATTR_ENDINDEX
+ const USHORT nMap2Count = nMap2End - nMap2Start + 1;
+ const USHORT nMap2New = 24; // ATTR_VALIDDATA - ATTR_STARTINDEX
+ pVersionMap2 = new USHORT [ nMap2Count ];
+ for ( i=0, j=nMap2Start; i < nMap2New; i++, j++ )
+ pVersionMap2[i] = j;
+ // zwei Eintraege eingefuegt...
+ for ( i=nMap2New, j=nMap2Start+nMap2New+2; i < nMap2Count; i++, j++ )
+ pVersionMap2[i] = j;
+
+ // dritte Map: ATTR_INDENT ab 350 eingefuegt
+
+ const USHORT nMap3Start = 100; // ATTR_STARTINDEX
+ const USHORT nMap3End = 160; // ATTR_ENDINDEX
+ const USHORT nMap3Count = nMap3End - nMap3Start + 1;
+ const USHORT nMap3New = 11; // ATTR_INDENT - ATTR_STARTINDEX
+ pVersionMap3 = new USHORT [ nMap3Count ];
+ for ( i=0, j=nMap3Start; i < nMap3New; i++, j++ )
+ pVersionMap3[i] = j;
+ // ein Eintrag eingefuegt...
+ for ( i=nMap3New, j=nMap3Start+nMap3New+1; i < nMap3Count; i++, j++ )
+ pVersionMap3[i] = j;
+
+ // vierte Map: ATTR_ROTATE_VALUE und ATTR_ROTATE_MODE ab 367 eingefuegt
+
+ const USHORT nMap4Start = 100; // ATTR_STARTINDEX
+ const USHORT nMap4End = 161; // ATTR_ENDINDEX
+ const USHORT nMap4Count = nMap4End - nMap4Start + 1;
+ const USHORT nMap4New = 14; // ATTR_ROTATE_VALUE - ATTR_STARTINDEX
+ pVersionMap4 = new USHORT [ nMap4Count ];
+ for ( i=0, j=nMap4Start; i < nMap4New; i++, j++ )
+ pVersionMap4[i] = j;
+ // zwei Eintraege eingefuegt...
+ for ( i=nMap4New, j=nMap4Start+nMap4New+2; i < nMap4Count; i++, j++ )
+ pVersionMap4[i] = j;
+
+ // fifth map: CJK..., CTL..., EMPHASISMARK, TWOLINES (12 items) added in 614
+
+ const USHORT nMap5Start = 100; // ATTR_STARTINDEX
+ const USHORT nMap5End = 163; // ATTR_ENDINDEX
+ const USHORT nMap5Count = nMap5End - nMap5Start + 1;
+ const USHORT nMap5New = 10; // ATTR_CJK_FONT - ATTR_STARTINDEX
+ pVersionMap5 = new USHORT [ nMap5Count ];
+ for ( i=0, j=nMap5Start; i < nMap5New; i++, j++ )
+ pVersionMap5[i] = j;
+ // 12 entries inserted
+ for ( i=nMap5New, j=nMap5Start+nMap5New+12; i < nMap5Count; i++, j++ )
+ pVersionMap5[i] = j;
+
+ // sixth map: ATTR_SCRIPTSPACE, ATTR_HANGPUNCTUATION, ATTR_FORBIDDEN_RULES added in 614d
+
+ const USHORT nMap6Start = 100; // ATTR_STARTINDEX
+ const USHORT nMap6End = 175; // ATTR_ENDINDEX
+ const USHORT nMap6Count = nMap6End - nMap6Start + 1;
+ const USHORT nMap6New = 22; // ATTR_SCRIPTSPACE - ATTR_STARTINDEX
+ pVersionMap6 = new USHORT [ nMap6Count ];
+ for ( i=0, j=nMap6Start; i < nMap6New; i++, j++ )
+ pVersionMap6[i] = j;
+ // 3 entries inserted
+ for ( i=nMap6New, j=nMap6Start+nMap6New+3; i < nMap6Count; i++, j++ )
+ pVersionMap6[i] = j;
+
+ // seventh map: ATTR_FONT_WORDLINE, ATTR_FONT_RELIEF, ATTR_HYPHENATE added in 632b
+
+ const USHORT nMap7Start = 100; // ATTR_STARTINDEX
+ const USHORT nMap7End = 178; // ATTR_ENDINDEX
+ const USHORT nMap7Count = nMap7End - nMap7Start + 1;
+ const USHORT nMap7New = 22; // ATTR_FONT_WORDLINE - ATTR_STARTINDEX
+ pVersionMap7 = new USHORT [ nMap7Count ];
+ for ( i=0, j=nMap7Start; i < nMap7New; i++, j++ )
+ pVersionMap7[i] = j;
+ // 3 entries inserted
+ for ( i=nMap7New, j=nMap7Start+nMap7New+3; i < nMap7Count; i++, j++ )
+ pVersionMap7[i] = j;
+
+ // eighth map: ATTR_VERTICAL_ASIAN added in 642q
+
+ const USHORT nMap8Start = 100; // ATTR_STARTINDEX
+ const USHORT nMap8End = 181; // ATTR_ENDINDEX
+ const USHORT nMap8Count = nMap8End - nMap8Start + 1;
+ const USHORT nMap8New = 34; // ATTR_VERTICAL_ASIAN - ATTR_STARTINDEX
+ pVersionMap8 = new USHORT [ nMap8Count ];
+ for ( i=0, j=nMap8Start; i < nMap8New; i++, j++ )
+ pVersionMap8[i] = j;
+ // 1 entry inserted
+ for ( i=nMap8New, j=nMap8Start+nMap8New+1; i < nMap8Count; i++, j++ )
+ pVersionMap8[i] = j;
+
+ // 9th map: ATTR_WRITINGDIR added in 643y
+
+ const USHORT nMap9Start = 100; // ATTR_STARTINDEX
+ const USHORT nMap9End = 182; // ATTR_ENDINDEX
+ const USHORT nMap9Count = nMap9End - nMap9Start + 1;
+ const USHORT nMap9New = 35; // ATTR_WRITINGDIR - ATTR_STARTINDEX
+ pVersionMap9 = new USHORT [ nMap9Count ];
+ for ( i=0, j=nMap9Start; i < nMap9New; i++, j++ )
+ pVersionMap9[i] = j;
+ // 1 entry inserted
+ for ( i=nMap9New, j=nMap9Start+nMap9New+1; i < nMap9Count; i++, j++ )
+ pVersionMap9[i] = j;
+
+ // ATTR_PAGE_SCALETO added in 680/sab008
+
+ // 10th map: ATTR_SHRINKTOFIT, ATTR_BORDER_TL_BR, ATTR_BORDER_BL_TR added in 680/dr14
+
+ const USHORT nMap10Start = 100; // ATTR_STARTINDEX
+ const USHORT nMap10End = 184; // ATTR_ENDINDEX
+ const USHORT nMap10Count = nMap10End - nMap10Start + 1;
+ const USHORT nMap10New = 37; // ATTR_SHRINKTOFIT - ATTR_STARTINDEX
+ pVersionMap10 = new USHORT [ nMap10Count ];
+ for ( i=0, j=nMap10Start; i < nMap10New; i++, j++ )
+ pVersionMap10[i] = j;
+ // 3 entries inserted
+ for ( i=nMap10New, j=nMap10Start+nMap10New+3; i < nMap10Count; i++, j++ )
+ pVersionMap10[i] = j;
+
+ // 11th map: ATTR_FONT_OVERLINE added in DEV300/overline2
+
+ const USHORT nMap11Start = 100; // ATTR_STARTINDEX
+ const USHORT nMap11End = 187; // ATTR_ENDINDEX
+ const USHORT nMap11Count = nMap11End - nMap11Start + 1;
+ const USHORT nMap11New = 5; // ATTR_FONT_OVERLINE - ATTR_STARTINDEX
+ pVersionMap11 = new USHORT [ nMap11Count ];
+ for ( i=0, j=nMap11Start; i < nMap11New; i++, j++ )
+ pVersionMap11[i] = j;
+ // 1 entry inserted
+ for ( i=nMap11New, j=nMap11Start+nMap11New+1; i < nMap11Count; i++, j++ )
+ pVersionMap11[i] = j;
+}
+
+void ScDocumentPool::DeleteVersionMaps()
+{
+ DBG_ASSERT( pVersionMap1 && pVersionMap2 &&
+ pVersionMap3 && pVersionMap4 &&
+ pVersionMap5 && pVersionMap6 &&
+ pVersionMap7 && pVersionMap8 &&
+ pVersionMap9 && pVersionMap10 &&
+ pVersionMap11, "DeleteVersionMaps without maps" );
+
+ delete[] pVersionMap11;
+ pVersionMap11 = 0;
+ delete[] pVersionMap10;
+ pVersionMap10 = 0;
+ delete[] pVersionMap9;
+ pVersionMap9 = 0;
+ delete[] pVersionMap8;
+ pVersionMap8 = 0;
+ delete[] pVersionMap7;
+ pVersionMap7 = 0;
+ delete[] pVersionMap6;
+ pVersionMap6 = 0;
+ delete[] pVersionMap5;
+ pVersionMap5 = 0;
+ delete[] pVersionMap4;
+ pVersionMap4 = 0;
+ delete[] pVersionMap3;
+ pVersionMap3 = 0;
+ delete[] pVersionMap2;
+ pVersionMap2 = 0;
+ delete[] pVersionMap1;
+ pVersionMap1 = 0;
+}
+
+// ----------------------------------------------------------------------------------------
+//
+// Fuer die Pattern-Attribute (SetItems) kann der USHORT RefCount leicht ueberlaufen
+// (z.B. 600 ganze Zeilen abwechselnd formatieren).
+// Darum wird der RefCount bei SC_MAX_POOLREF festgehalten und nicht mehr hoch- oder
+// heruntergezaehlt. Dieser RefCount wird dann erst beim naechsten Laden neu gezaehlt.
+// Die Differenz zwischen SC_MAX_POOLREF und SC_SAFE_POOLREF ist ein wenig groesser
+// als noetig, um zu erkennen, wenn der RefCount aus Versehen doch "normal" veraendert
+// wird (Assertions).
+//
+
+const SfxPoolItem& __EXPORT ScDocumentPool::Put( const SfxPoolItem& rItem, USHORT nWhich )
+{
+ if ( rItem.Which() != ATTR_PATTERN ) // nur Pattern ist special
+ return SfxItemPool::Put( rItem, nWhich );
+
+ // das Default-Pattern dieses Pools nicht kopieren
+ if (&rItem == ppPoolDefaults[ ATTR_PATTERN - ATTR_STARTINDEX ])
+ return rItem;
+
+ // ansonsten muss Put immer passieren, weil es ein anderer Pool sein kann
+ const SfxPoolItem& rNew = SfxItemPool::Put( rItem, nWhich );
+ CheckRef( rNew );
+ return rNew;
+}
+
+void __EXPORT ScDocumentPool::Remove( const SfxPoolItem& rItem )
+{
+ if ( rItem.Which() == ATTR_PATTERN ) // nur Pattern ist special
+ {
+ ULONG nRef = rItem.GetRefCount();
+ if ( nRef >= (ULONG) SC_MAX_POOLREF && nRef <= (ULONG) SFX_ITEMS_OLD_MAXREF )
+ {
+ if ( nRef != (ULONG) SC_SAFE_POOLREF )
+ {
+ DBG_ERROR("Wer fummelt da an meinen Ref-Counts herum");
+ SetRefCount( (SfxPoolItem&)rItem, (ULONG) SC_SAFE_POOLREF );
+ }
+ return; // nicht herunterzaehlen
+ }
+ }
+ SfxItemPool::Remove( rItem );
+}
+
+void ScDocumentPool::CheckRef( const SfxPoolItem& rItem ) // static
+{
+ ULONG nRef = rItem.GetRefCount();
+ if ( nRef >= (ULONG) SC_MAX_POOLREF && nRef <= (ULONG) SFX_ITEMS_OLD_MAXREF )
+ {
+ // beim Apply vom Cache wird evtl. um 2 hochgezaehlt (auf MAX+1 oder SAFE+2),
+ // heruntergezaehlt wird nur einzeln (in LoadCompleted)
+ DBG_ASSERT( nRef<=(ULONG)SC_MAX_POOLREF+1 || (nRef>=(ULONG)SC_SAFE_POOLREF-1 && nRef<=(ULONG)SC_SAFE_POOLREF+2),
+ "ScDocumentPool::CheckRef" );
+ SetRefCount( (SfxPoolItem&)rItem, (ULONG) SC_SAFE_POOLREF );
+ }
+}
+
+// ----------------------------------------------------------------------------------------
+
+void ScDocumentPool::StyleDeleted( ScStyleSheet* pStyle )
+{
+ USHORT nCount = GetItemCount(ATTR_PATTERN);
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ScPatternAttr* pPattern = (ScPatternAttr*)GetItem(ATTR_PATTERN, i);
+ if ( pPattern && pPattern->GetStyleSheet() == pStyle )
+ pPattern->StyleToName();
+ }
+}
+
+SfxItemPool* __EXPORT ScDocumentPool::Clone() const
+{
+ return new SfxItemPool (*this, TRUE);
+}
+
+SfxItemPresentation lcl_HFPresentation
+(
+ const SfxPoolItem& rItem,
+ SfxItemPresentation ePresentation,
+ SfxMapUnit eCoreMetric,
+ SfxMapUnit ePresentationMetric,
+ String& rText,
+ const IntlWrapper* pIntl
+)
+{
+ const SfxItemSet& rSet = ((const SfxSetItem&)rItem).GetItemSet();
+ const SfxPoolItem* pItem;
+
+ if ( SFX_ITEM_SET == rSet.GetItemState(ATTR_PAGE_ON,FALSE,&pItem) )
+ {
+ if( FALSE == ((const SfxBoolItem*)pItem)->GetValue() )
+ return SFX_ITEM_PRESENTATION_NONE;
+ }
+
+ SfxItemIter aIter( rSet );
+ pItem = aIter.FirstItem();
+ String aText;
+ String aDel = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM( " + " ));
+
+ while( pItem )
+ {
+ USHORT nWhich = pItem->Which();
+
+ aText.Erase();
+
+ switch( nWhich )
+ {
+ case ATTR_PAGE_ON:
+ case ATTR_PAGE_DYNAMIC:
+ case ATTR_PAGE_SHARED:
+ break;
+
+ case ATTR_LRSPACE:
+ {
+ SvxLRSpaceItem& rLRItem = (SvxLRSpaceItem&)*pItem;
+ USHORT nPropLeftMargin = rLRItem.GetPropLeft();
+ USHORT nPropRightMargin = rLRItem.GetPropRight();
+ USHORT nLeftMargin, nRightMargin;
+ long nTmp;
+ nTmp = rLRItem.GetLeft();
+ nLeftMargin = nTmp < 0 ? 0 : USHORT(nTmp);
+ nTmp = rLRItem.GetRight();
+ nRightMargin = nTmp < 0 ? 0 : USHORT(nTmp);
+
+ aText = SVX_RESSTR(RID_SVXITEMS_LRSPACE_LEFT);
+ if ( 100 != nPropLeftMargin )
+ {
+ aText += String::CreateFromInt32( nPropLeftMargin );
+ aText += '%';
+ }
+ else
+ {
+ aText += GetMetricText( (long)nLeftMargin,
+ eCoreMetric, ePresentationMetric, pIntl );
+ aText += SVX_RESSTR(GetMetricId(ePresentationMetric));
+ }
+ aText += cpDelim;
+
+ // nPropFirstLineOfst haben wir nicht
+
+ aText += SVX_RESSTR(RID_SVXITEMS_LRSPACE_RIGHT);
+ if ( 100 != nPropRightMargin )
+ {
+ aText += String::CreateFromInt32( nPropRightMargin );
+ aText += '%';
+ }
+ else
+ {
+ aText += GetMetricText( (long)nRightMargin,
+ eCoreMetric, ePresentationMetric, pIntl );
+ aText += SVX_RESSTR(GetMetricId(ePresentationMetric));
+ }
+ }
+ break;
+
+ default:
+ if ( !pIntl )
+ pIntl = ScGlobal::pScIntlWrapper;
+ pItem->GetPresentation( ePresentation, eCoreMetric, ePresentationMetric, aText, pIntl );
+
+ }
+
+ if ( aText.Len() )
+ {
+ rText += aText;
+ rText += aDel;
+ }
+
+ pItem = aIter.NextItem();
+ }
+
+ rText.EraseTrailingChars();
+ rText.EraseTrailingChars( '+' );
+ rText.EraseTrailingChars();
+
+ return ePresentation;
+}
+
+SfxItemPresentation __EXPORT ScDocumentPool::GetPresentation(
+ const SfxPoolItem& rItem,
+ SfxItemPresentation ePresentation,
+ SfxMapUnit ePresentationMetric,
+ String& rText,
+ const IntlWrapper* pIntl ) const
+{
+ USHORT nW = rItem.Which();
+ String aStrYes ( ScGlobal::GetRscString(STR_YES) );
+ String aStrNo ( ScGlobal::GetRscString(STR_NO) );
+ String aStrSep = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM(": "));
+
+ switch( nW )
+ {
+ case ATTR_PAGE_TOPDOWN:
+ switch ( ePresentation )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText = ScGlobal::GetRscString(STR_SCATTR_PAGE_PRINTDIR);
+ rText += aStrSep;
+// break; // DURCHFALLEN!!!
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText += ((const SfxBoolItem&)rItem).GetValue() ?
+ ScGlobal::GetRscString(STR_SCATTR_PAGE_TOPDOWN) :
+ ScGlobal::GetRscString(STR_SCATTR_PAGE_LEFTRIGHT) ;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ break;
+
+ case ATTR_PAGE_HEADERS:
+ switch ( ePresentation )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText = ScGlobal::GetRscString(STR_SCATTR_PAGE_HEADERS);
+ rText += aStrSep;
+// break; // DURCHFALLEN!!!
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText += ((const SfxBoolItem&)rItem).GetValue() ? aStrYes : aStrNo ;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ break;
+
+ case ATTR_PAGE_NULLVALS:
+ switch ( ePresentation )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText = ScGlobal::GetRscString(STR_SCATTR_PAGE_NULLVALS);
+ rText += aStrSep;
+// break; // DURCHFALLEN!!!
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText += ((const SfxBoolItem&)rItem).GetValue() ? aStrYes : aStrNo ;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ break;
+
+ case ATTR_PAGE_FORMULAS:
+ switch ( ePresentation )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText = ScGlobal::GetRscString(STR_SCATTR_PAGE_FORMULAS);
+ rText += aStrSep;
+// break; // DURCHFALLEN!!!
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText += ((const SfxBoolItem&)rItem).GetValue() ? aStrYes : aStrNo ;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ break;
+
+ case ATTR_PAGE_NOTES:
+ switch ( ePresentation )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText = ScGlobal::GetRscString(STR_SCATTR_PAGE_NOTES);
+ rText += aStrSep;
+// break; // DURCHFALLEN!!!
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText += ((const SfxBoolItem&)rItem).GetValue() ? aStrYes : aStrNo ;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ break;
+
+ case ATTR_PAGE_GRID:
+ switch ( ePresentation )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText = ScGlobal::GetRscString(STR_SCATTR_PAGE_GRID);
+ rText += aStrSep;
+// break; // DURCHFALLEN!!!
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText += ((const SfxBoolItem&)rItem).GetValue() ? aStrYes : aStrNo ;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ break;
+
+ case ATTR_PAGE_SCALETOPAGES:
+ {
+ USHORT nPagNo = ((const SfxUInt16Item&)rItem).GetValue();
+
+ if( nPagNo )
+ {
+ switch ( ePresentation )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ {
+ rText.Assign( ScGlobal::GetRscString( STR_SCATTR_PAGE_SCALETOPAGES ) ).Append( aStrSep );
+ }
+// break; // DURCHFALLEN!!!
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ {
+ String aPages( ScGlobal::GetRscString( STR_SCATTR_PAGE_SCALE_PAGES ) );
+ aPages.SearchAndReplaceAscii( "%1", String::CreateFromInt32( nPagNo ) );
+ rText.Append( aPages );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ {
+ ePresentation = SFX_ITEM_PRESENTATION_NONE;
+ }
+ }
+ break;
+
+ case ATTR_PAGE_FIRSTPAGENO:
+ {
+ USHORT nPagNo = ((const SfxUInt16Item&)rItem).GetValue();
+
+ if( nPagNo )
+ {
+ switch ( ePresentation )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText = ScGlobal::GetRscString(STR_SCATTR_PAGE_FIRSTPAGENO);
+ rText += aStrSep;
+// break; // DURCHFALLEN!!!
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText += String::CreateFromInt32( nPagNo );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ {
+ ePresentation = SFX_ITEM_PRESENTATION_NONE;
+ }
+ }
+ break;
+
+ case ATTR_PAGE_SCALE:
+ {
+ USHORT nPercent = ((const SfxUInt16Item&)rItem).GetValue();
+
+ if( nPercent )
+ {
+ switch ( ePresentation )
+ {
+ case SFX_ITEM_PRESENTATION_COMPLETE:
+ rText = ScGlobal::GetRscString(STR_SCATTR_PAGE_SCALE);
+ rText += aStrSep;
+// break; // DURCHFALLEN!!!
+ case SFX_ITEM_PRESENTATION_NAMELESS:
+ rText += String::CreateFromInt32( nPercent );
+ rText += '%';
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ {
+ ePresentation = SFX_ITEM_PRESENTATION_NONE;
+ }
+ }
+ break;
+
+ case ATTR_PAGE_HEADERSET:
+ {
+ String aBuffer;
+
+ if( lcl_HFPresentation( rItem, ePresentation, GetMetric( nW ), ePresentationMetric, aBuffer, pIntl ) != SFX_ITEM_PRESENTATION_NONE )
+ {
+ rText = ScGlobal::GetRscString(STR_HEADER);
+ rText.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " ( " ));
+ rText += aBuffer;
+ rText.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " ) " ));
+ }
+ }
+ break;
+
+ case ATTR_PAGE_FOOTERSET:
+ {
+ String aBuffer;
+
+ if( lcl_HFPresentation( rItem, ePresentation, GetMetric( nW ), ePresentationMetric, aBuffer, pIntl ) != SFX_ITEM_PRESENTATION_NONE )
+ {
+ rText = ScGlobal::GetRscString(STR_FOOTER);
+ rText.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " ( " ));
+ rText += aBuffer;
+ rText.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " ) " ));
+ }
+ }
+ break;
+
+/*
+ case ATTR_PAGE_HEADERLEFT:
+ rText = "SID_SCATTR_PAGE_HEADERLEFT";
+ break;
+
+ case ATTR_PAGE_FOOTERLEFT:
+ rText = "SID_SCATTR_PAGE_FOOTERLEFT";
+ break;
+
+ case ATTR_PAGE_HEADERRIGHT:
+ rText = "SID_SCATTR_PAGE_HEADERRIGHT";
+ break;
+
+ case ATTR_PAGE_FOOTERRIGHT:
+ rText = "SID_SCATTR_PAGE_FOOTERRIGHT";
+ break;
+*/
+
+ default:
+ if ( !pIntl )
+ pIntl = ScGlobal::pScIntlWrapper;
+ ePresentation = rItem.GetPresentation( ePresentation, GetMetric( nW ), ePresentationMetric, rText, pIntl );
+ break;
+ }
+
+ return ePresentation;
+}
+
+SfxMapUnit __EXPORT ScDocumentPool::GetMetric( USHORT nWhich ) const
+{
+ // eigene Attribute: Twips, alles andere 1/100 mm
+
+ if ( nWhich >= ATTR_STARTINDEX && nWhich <= ATTR_ENDINDEX )
+ return SFX_MAPUNIT_TWIP;
+ else
+ return SFX_MAPUNIT_100TH_MM;
+}
+
+
+
+
+
diff --git a/sc/source/core/data/documen2.cxx b/sc/source/core/data/documen2.cxx
new file mode 100644
index 000000000000..1ef50cf30fd7
--- /dev/null
+++ b/sc/source/core/data/documen2.cxx
@@ -0,0 +1,1271 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: documen2.cxx,v $
+ * $Revision: 1.75.18.1 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#define _ZFORLIST_DECLARE_TABLE
+#include "scitems.hxx"
+#include <svx/eeitem.hxx>
+
+#include <svx/editeng.hxx>
+#include <svx/forbiddencharacterstable.hxx>
+#include <svx/linkmgr.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdobj.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/printer.hxx>
+#include <svtools/zforlist.hxx>
+#include <svtools/zformat.hxx>
+#include <vcl/virdev.hxx>
+#include <comphelper/processfactory.hxx>
+#include <svtools/PasswordHelper.hxx>
+#include <tools/tenccvt.hxx>
+#include <tools/list.hxx>
+#include <rtl/crc.h>
+
+#include "document.hxx"
+#include "table.hxx"
+#include "attrib.hxx"
+#include "patattr.hxx"
+#include "rangenam.hxx"
+#include "dbcolect.hxx"
+#include "pivot.hxx"
+#include "docpool.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "globstr.hrc"
+#include "chartarr.hxx"
+#include "chartlock.hxx"
+#include "rechead.hxx"
+#include "global.hxx"
+#include "brdcst.hxx"
+#include "bcaslot.hxx"
+#include "adiasync.hxx"
+#include "addinlis.hxx"
+#include "chartlis.hxx"
+#include "markdata.hxx"
+#include "conditio.hxx"
+#include "validat.hxx"
+#include "progress.hxx"
+#include "detdata.hxx"
+#include "sc.hrc" // FID_DATACHANGED
+#include "ddelink.hxx"
+#include "chgtrack.hxx"
+#include "chgviset.hxx"
+#include "editutil.hxx"
+#include "hints.hxx"
+#include "dpobject.hxx"
+#include "indexmap.hxx"
+#include "scrdata.hxx"
+#include "poolhelp.hxx"
+#include "unoreflist.hxx"
+#include "listenercalls.hxx"
+#include "recursionhelper.hxx"
+#include "lookupcache.hxx"
+#include "externalrefmgr.hxx"
+
+// pImpl because including lookupcache.hxx in document.hxx isn't wanted, and
+// dtor plus helpers are convenient.
+struct ScLookupCacheMapImpl
+{
+ ScLookupCacheMap aCacheMap;
+ ~ScLookupCacheMapImpl()
+ {
+ freeCaches();
+ }
+ void clear()
+ {
+ freeCaches();
+ // Zap map.
+ ScLookupCacheMap aTmp;
+ aCacheMap.swap( aTmp);
+ }
+private:
+ void freeCaches()
+ {
+ for (ScLookupCacheMap::iterator it( aCacheMap.begin()); it != aCacheMap.end(); ++it)
+ delete (*it).second;
+ }
+};
+
+// STATIC DATA -----------------------------------------------------------
+
+ScDocument::ScDocument( ScDocumentMode eMode,
+ SfxObjectShell* pDocShell ) :
+ xServiceManager( ::comphelper::getProcessServiceFactory() ),
+ pEditEngine( NULL ),
+ pNoteEngine( NULL ),
+ pNoteItemPool( NULL ),
+ pShell( pDocShell ),
+ pPrinter( NULL ),
+ pVirtualDevice_100th_mm( NULL ),
+ pDrawLayer( NULL ),
+ pColorTable( NULL ),
+ pCondFormList( NULL ),
+ pValidationList( NULL ),
+ pFormatExchangeList( NULL ),
+ pDPCollection( NULL ),
+ pLinkManager( NULL ),
+ pFormulaTree( NULL ),
+ pEOFormulaTree( NULL ),
+ pFormulaTrack( NULL ),
+ pEOFormulaTrack( NULL ),
+ pOtherObjects( NULL ),
+ pClipData( NULL ),
+ pDetOpList(NULL),
+ pChangeTrack( NULL ),
+ pUnoBroadcaster( NULL ),
+ pUnoListenerCalls( NULL ),
+ pUnoRefUndoList( NULL ),
+ pChangeViewSettings( NULL ),
+ pScriptTypeData( NULL ),
+ pCacheFieldEditEngine( NULL ),
+ pExternalRefMgr( NULL ),
+ pViewOptions( NULL ),
+ pDocOptions( NULL ),
+ pExtDocOptions( NULL ),
+ pConsolidateDlgData( NULL ),
+ pRecursionHelper( NULL ),
+ pAutoNameCache( NULL ),
+ pLookupCacheMapImpl( NULL ),
+ nUnoObjectId( 0 ),
+ nRangeOverflowType( 0 ),
+ aCurTextWidthCalcPos(MAXCOL,0,0),
+ nFormulaCodeInTree(0),
+ nXMLImportedFormulaCount( 0 ),
+ nInterpretLevel(0),
+ nMacroInterpretLevel(0),
+ nInterpreterTableOpLevel(0),
+ nMaxTableNumber( 0 ),
+ nSrcVer( SC_CURRENT_VERSION ),
+ nSrcMaxRow( MAXROW ),
+ nFormulaTrackCount(0),
+ nHardRecalcState(0),
+ nVisibleTab( 0 ),
+ eLinkMode(LM_UNKNOWN),
+ bProtected( FALSE ),
+ bAutoCalc( eMode == SCDOCMODE_DOCUMENT ),
+ bAutoCalcShellDisabled( FALSE ),
+ bForcedFormulaPending( FALSE ),
+ bCalculatingFormulaTree( FALSE ),
+ bIsClip( eMode == SCDOCMODE_CLIP ),
+ bCutMode( FALSE ),
+ bIsUndo( eMode == SCDOCMODE_UNDO ),
+ bIsVisible( FALSE ),
+ bIsEmbedded( FALSE ),
+// bNoSetDirty( TRUE ),
+ bNoSetDirty( FALSE ),
+ bInsertingFromOtherDoc( FALSE ),
+ bImportingXML( FALSE ),
+ bXMLFromWrapper( FALSE ),
+ bCalcingAfterLoad( FALSE ),
+ bNoListening( FALSE ),
+ bLoadingDone( TRUE ),
+ bIdleDisabled( FALSE ),
+ bInLinkUpdate( FALSE ),
+ bChartListenerCollectionNeedsUpdate( FALSE ),
+ bHasForcedFormulas( FALSE ),
+ bInDtorClear( FALSE ),
+ bExpandRefs( FALSE ),
+ bDetectiveDirty( FALSE ),
+ nMacroCallMode( SC_MACROCALL_ALLOWED ),
+ bHasMacroFunc( FALSE ),
+ nVisSpellState( 0 ),
+ nAsianCompression(SC_ASIANCOMPRESSION_INVALID),
+ nAsianKerning(SC_ASIANKERNING_INVALID),
+ bSetDrawDefaults( FALSE ),
+ bPastingDrawFromOtherDoc( FALSE ),
+ nInDdeLinkUpdate( 0 ),
+ bInUnoBroadcast( FALSE ),
+ bInUnoListenerCall( FALSE ),
+ eGrammar( formula::FormulaGrammar::GRAM_NATIVE ),
+ bStyleSheetUsageInvalid( TRUE ),
+ bUndoEnabled( TRUE ),
+ mbAdjustHeightEnabled( true ),
+ mbExecuteLinkEnabled( true ),
+ mbChangeReadOnlyEnabled( false ),
+ mnNamedRangesLockCount( 0 )
+{
+ SetStorageGrammar( formula::FormulaGrammar::GRAM_STORAGE_DEFAULT);
+
+ eSrcSet = gsl_getSystemTextEncoding();
+
+ if ( eMode == SCDOCMODE_DOCUMENT )
+ {
+ if ( pDocShell )
+ pLinkManager = new SvxLinkManager( pDocShell );
+
+ xPoolHelper = new ScPoolHelper( this );
+
+ pTab[0] = NULL;
+ pBASM = new ScBroadcastAreaSlotMachine( this );
+ pChartListenerCollection = new ScChartListenerCollection( this );
+ pRefreshTimerControl = new ScRefreshTimerControl;
+ }
+ else
+ {
+ pTab[0] = NULL;
+ pBASM = NULL;
+ pChartListenerCollection = NULL;
+ pRefreshTimerControl = NULL;
+ }
+
+ for (SCTAB i=1; i<=MAXTAB; i++)
+ pTab[i] = NULL;
+
+ pRangeName = new ScRangeName( 4, 4, FALSE, this );
+ pDBCollection = new ScDBCollection( 4, 4, FALSE, this );
+#if OLD_PIVOT_IMPLEMENTATION
+ pPivotCollection = new ScPivotCollection(4, 4, this );
+#endif
+ pSelectionAttr = NULL;
+ pChartCollection = new ScChartCollection;
+ apTemporaryChartLock = std::auto_ptr< ScTemporaryChartLock >( new ScTemporaryChartLock(this) );
+ xColNameRanges = new ScRangePairList;
+ xRowNameRanges = new ScRangePairList;
+ ImplCreateOptions();
+ // languages for a visible document are set by docshell later (from options)
+ SetLanguage( ScGlobal::eLnge, ScGlobal::eLnge, ScGlobal::eLnge );
+
+ aTrackTimer.SetTimeoutHdl( LINK( this, ScDocument, TrackTimeHdl ) );
+ aTrackTimer.SetTimeout( 100 );
+}
+
+
+void ScDocument::SetStorageGrammar( formula::FormulaGrammar::Grammar eGram )
+{
+ DBG_ASSERT(
+ eGram == formula::FormulaGrammar::GRAM_ODFF ||
+ eGram == formula::FormulaGrammar::GRAM_PODF,
+ "ScDocument::SetStorageGrammar: wrong storage grammar");
+
+ eStorageGrammar = eGram;
+
+ // FIXME: the XML import shouldn't strip brackets, the compiler should
+ // digest them instead, which could also speedup reference recognition
+ // during import.
+
+ eXmlImportGrammar = formula::FormulaGrammar::mergeToGrammar( eGram,
+ formula::FormulaGrammar::CONV_OOO);
+}
+
+
+void ScDocument::SetDocVisible( BOOL bSet )
+{
+ // called from view ctor - only for a visible document,
+ // each new sheet's RTL flag is initialized from the locale
+ bIsVisible = bSet;
+}
+
+
+sal_uInt32 ScDocument::GetDocumentID() const
+{
+ const ScDocument* pThis = this;
+ sal_uInt32 nCrc = rtl_crc32( 0, &pThis, sizeof(ScDocument*) );
+ // the this pointer only might not be sufficient
+ nCrc = rtl_crc32( nCrc, &pShell, sizeof(SfxObjectShell*) );
+ return nCrc;
+}
+
+
+void ScDocument::StartChangeTracking()
+{
+ if (!pChangeTrack)
+ pChangeTrack = new ScChangeTrack( this );
+}
+
+void ScDocument::EndChangeTracking()
+{
+ delete pChangeTrack;
+ pChangeTrack = NULL;
+}
+
+void ScDocument::SetChangeTrack( ScChangeTrack* pTrack )
+{
+ DBG_ASSERT( pTrack->GetDocument() == this, "SetChangeTrack: different documents" );
+ if ( !pTrack || pTrack == pChangeTrack || pTrack->GetDocument() != this )
+ return ;
+ EndChangeTracking();
+ pChangeTrack = pTrack;
+}
+
+
+IMPL_LINK( ScDocument, TrackTimeHdl, Timer*, EMPTYARG )
+{
+ if ( ScDdeLink::IsInUpdate() ) // nicht verschachteln
+ {
+ aTrackTimer.Start(); // spaeter nochmal versuchen
+ }
+ else if (pShell) // ausfuehren
+ {
+ TrackFormulas();
+ pShell->Broadcast( SfxSimpleHint( FID_DATACHANGED ) );
+ ResetChanged( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB) );
+
+ // modified...
+
+ if (!pShell->IsModified())
+ {
+ pShell->SetModified( TRUE );
+ SfxBindings* pBindings = GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( SID_SAVEDOC );
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ }
+ }
+ }
+
+ return 0;
+}
+
+void ScDocument::StartTrackTimer()
+{
+ if (!aTrackTimer.IsActive()) // nicht ewig aufschieben
+ aTrackTimer.Start();
+}
+
+ScDocument::~ScDocument()
+{
+ DBG_ASSERT( !bInLinkUpdate, "bInLinkUpdate in dtor" );
+
+ bInDtorClear = TRUE;
+
+ // first of all disable all refresh timers by deleting the control
+ if ( pRefreshTimerControl )
+ { // To be sure there isn't anything running do it with a protector,
+ // this ensures also that nothing needs the control anymore.
+ ScRefreshTimerProtector aProt( GetRefreshTimerControlAddress() );
+ delete pRefreshTimerControl, pRefreshTimerControl = NULL;
+ }
+
+ // Links aufrauemen
+
+ if ( pLinkManager )
+ {
+ // BaseLinks freigeben
+ for ( USHORT n = pLinkManager->GetServers().Count(); n; )
+ pLinkManager->GetServers()[ --n ]->Closed();
+
+ if ( pLinkManager->GetLinks().Count() )
+ pLinkManager->Remove( 0, pLinkManager->GetLinks().Count() );
+ }
+
+ if (pExternalRefMgr.get())
+ // Destroy the external ref mgr instance here because it has a timer
+ // which needs to be stopped before the app closes.
+ pExternalRefMgr.reset(NULL);
+
+ ScAddInAsync::RemoveDocument( this );
+ ScAddInListener::RemoveDocument( this );
+ delete pChartListenerCollection; // vor pBASM wg. evtl. Listener!
+ pChartListenerCollection = NULL;
+ DELETEZ( pLookupCacheMapImpl); // before pBASM because of listeners
+ // BroadcastAreas vor allen Zellen zerstoeren um unnoetige
+ // Einzel-EndListenings der Formelzellen zu vermeiden
+ delete pBASM; // BroadcastAreaSlotMachine
+ pBASM = NULL;
+
+ if (pUnoBroadcaster)
+ {
+ delete pUnoBroadcaster; // broadcasted nochmal SFX_HINT_DYING
+ pUnoBroadcaster = NULL;
+ }
+
+ delete pUnoRefUndoList;
+ delete pUnoListenerCalls;
+
+ Clear( sal_True ); // TRUE = from destructor (needed for SdrModel::ClearModel)
+
+ if (pCondFormList)
+ {
+ pCondFormList->DeleteAndDestroy( 0, pCondFormList->Count() );
+ DELETEZ(pCondFormList);
+ }
+ if (pValidationList)
+ {
+ pValidationList->DeleteAndDestroy( 0, pValidationList->Count() );
+ DELETEZ(pValidationList);
+ }
+ delete pRangeName;
+ delete pDBCollection;
+#if OLD_PIVOT_IMPLEMENTATION
+ delete pPivotCollection;
+#endif
+ delete pSelectionAttr;
+ apTemporaryChartLock.reset();
+ delete pChartCollection;
+ DeleteDrawLayer();
+ delete pFormatExchangeList;
+ delete pPrinter;
+ ImplDeleteOptions();
+ delete pConsolidateDlgData;
+ delete pLinkManager;
+ delete pClipData;
+ delete pDetOpList; // loescht auch die Eintraege
+ delete pChangeTrack;
+ delete pEditEngine;
+ delete pNoteEngine;
+ SfxItemPool::Free(pNoteItemPool);
+ delete pChangeViewSettings; // und weg damit
+ delete pVirtualDevice_100th_mm;
+
+ delete pDPCollection;
+
+ // delete the EditEngine before destroying the xPoolHelper
+ delete pCacheFieldEditEngine;
+
+ if ( xPoolHelper.isValid() && !bIsClip )
+ xPoolHelper->SourceDocumentGone();
+ xPoolHelper.unbind();
+
+ DeleteColorTable();
+ delete pScriptTypeData;
+ delete pOtherObjects;
+ delete pRecursionHelper;
+
+ DBG_ASSERT( !pAutoNameCache, "AutoNameCache still set in dtor" );
+}
+
+void ScDocument::InitClipPtrs( ScDocument* pSourceDoc )
+{
+ DBG_ASSERT(bIsClip, "InitClipPtrs und nicht bIsClip");
+
+ if (pCondFormList)
+ {
+ pCondFormList->DeleteAndDestroy( 0, pCondFormList->Count() );
+ DELETEZ(pCondFormList);
+ }
+ if (pValidationList)
+ {
+ pValidationList->DeleteAndDestroy( 0, pValidationList->Count() );
+ DELETEZ(pValidationList);
+ }
+
+ Clear();
+
+ xPoolHelper = pSourceDoc->xPoolHelper;
+
+ // bedingte Formate / Gueltigkeiten
+ //! Vorlagen kopieren?
+ const ScConditionalFormatList* pSourceCond = pSourceDoc->pCondFormList;
+ if ( pSourceCond )
+ pCondFormList = new ScConditionalFormatList(this, *pSourceCond);
+ const ScValidationDataList* pSourceValid = pSourceDoc->pValidationList;
+ if ( pSourceValid )
+ pValidationList = new ScValidationDataList(this, *pSourceValid);
+
+ // Links in Stream speichern
+ delete pClipData;
+ if (pSourceDoc->HasDdeLinks())
+ {
+ pClipData = new SvMemoryStream;
+ pSourceDoc->SaveDdeLinks(*pClipData);
+ }
+ else
+ pClipData = NULL;
+
+ // Options pointers exist (ImplCreateOptions) for any document.
+ // Must be copied for correct results in OLE objects (#i42666#).
+ SetDocOptions( pSourceDoc->GetDocOptions() );
+ SetViewOptions( pSourceDoc->GetViewOptions() );
+}
+
+SvNumberFormatter* ScDocument::GetFormatTable() const
+{
+ return xPoolHelper->GetFormTable();
+}
+
+SfxItemPool* ScDocument::GetEditPool() const
+{
+ return xPoolHelper->GetEditPool();
+}
+
+SfxItemPool* ScDocument::GetEnginePool() const
+{
+ return xPoolHelper->GetEnginePool();
+}
+
+ScFieldEditEngine& ScDocument::GetEditEngine()
+{
+ if ( !pEditEngine )
+ {
+ pEditEngine = new ScFieldEditEngine( GetEnginePool(), GetEditPool() );
+ pEditEngine->SetUpdateMode( FALSE );
+ pEditEngine->EnableUndo( FALSE );
+ pEditEngine->SetRefMapMode( MAP_100TH_MM );
+ pEditEngine->SetForbiddenCharsTable( xForbiddenCharacters );
+ }
+ return *pEditEngine;
+}
+
+ScNoteEditEngine& ScDocument::GetNoteEngine()
+{
+ if ( !pNoteEngine )
+ {
+ pNoteEngine = new ScNoteEditEngine( GetEnginePool(), GetEditPool() );
+ pNoteEngine->SetUpdateMode( FALSE );
+ pNoteEngine->EnableUndo( FALSE );
+ pNoteEngine->SetRefMapMode( MAP_100TH_MM );
+ pNoteEngine->SetForbiddenCharsTable( xForbiddenCharacters );
+ const SfxItemSet& rItemSet = GetDefPattern()->GetItemSet();
+ SfxItemSet* pEEItemSet = new SfxItemSet( pNoteEngine->GetEmptyItemSet() );
+ ScPatternAttr::FillToEditItemSet( *pEEItemSet, rItemSet );
+ pNoteEngine->SetDefaults( pEEItemSet ); // edit engine takes ownership
+ }
+ return *pNoteEngine;
+}
+
+SfxItemPool& ScDocument::GetNoteItemPool()
+{
+ if ( !pNoteItemPool )
+ pNoteItemPool = new SfxItemPool(SdrObject::GetGlobalDrawObjectItemPool());
+ return *pNoteItemPool;
+}
+
+void ScDocument::ResetClip( ScDocument* pSourceDoc, const ScMarkData* pMarks )
+{
+ if (bIsClip)
+ {
+ InitClipPtrs(pSourceDoc);
+
+ for (SCTAB i = 0; i <= MAXTAB; i++)
+ if (pSourceDoc->pTab[i])
+ if (!pMarks || pMarks->GetTableSelect(i))
+ {
+ String aString;
+ pSourceDoc->pTab[i]->GetName(aString);
+ pTab[i] = new ScTable(this, i, aString);
+ pTab[i]->SetLayoutRTL( pSourceDoc->pTab[i]->IsLayoutRTL() );
+ nMaxTableNumber = i+1;
+ }
+ }
+ else
+ {
+ DBG_ERROR("ResetClip");
+ }
+}
+
+void ScDocument::ResetClip( ScDocument* pSourceDoc, SCTAB nTab )
+{
+ if (bIsClip)
+ {
+ InitClipPtrs(pSourceDoc);
+
+ pTab[nTab] = new ScTable(this, nTab,
+ String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("baeh")));
+ if (pSourceDoc->pTab[nTab])
+ pTab[nTab]->SetLayoutRTL( pSourceDoc->pTab[nTab]->IsLayoutRTL() );
+ nMaxTableNumber = nTab+1;
+ }
+ else
+ {
+ DBG_ERROR("ResetClip");
+ }
+}
+
+void ScDocument::DeleteNumberFormat( const sal_uInt32* /* pDelKeys */, sal_uInt32 /* nCount */ )
+{
+/*
+ for (ULONG i = 0; i < nCount; i++)
+ xPoolHelper->GetFormTable()->DeleteEntry(pDelKeys[i]);
+*/
+}
+
+void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ ScBaseCell* pCell, ULONG nFormatIndex, BOOL bForceTab )
+{
+ if (VALIDTAB(nTab))
+ {
+ if ( bForceTab && !pTab[nTab] )
+ {
+ BOOL bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
+
+ pTab[nTab] = new ScTable(this, nTab,
+ String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
+ bExtras, bExtras);
+ }
+
+ if (pTab[nTab])
+ pTab[nTab]->PutCell( nCol, nRow, nFormatIndex, pCell );
+ }
+}
+
+void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell,
+ ULONG nFormatIndex, BOOL bForceTab )
+{
+ SCTAB nTab = rPos.Tab();
+ if ( bForceTab && !pTab[nTab] )
+ {
+ BOOL bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
+
+ pTab[nTab] = new ScTable(this, nTab,
+ String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
+ bExtras, bExtras);
+ }
+
+ if (pTab[nTab])
+ pTab[nTab]->PutCell( rPos, nFormatIndex, pCell );
+}
+
+BOOL ScDocument::GetPrintArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow,
+ BOOL bNotes ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ {
+ BOOL bAny = pTab[nTab]->GetPrintArea( rEndCol, rEndRow, bNotes );
+ if (pDrawLayer)
+ {
+ ScRange aDrawRange(0,0,nTab, MAXCOL,MAXROW,nTab);
+ if (DrawGetPrintArea( aDrawRange, TRUE, TRUE ))
+ {
+ if (aDrawRange.aEnd.Col()>rEndCol) rEndCol=aDrawRange.aEnd.Col();
+ if (aDrawRange.aEnd.Row()>rEndRow) rEndRow=aDrawRange.aEnd.Row();
+ bAny = TRUE;
+ }
+ }
+ return bAny;
+ }
+
+ rEndCol = 0;
+ rEndRow = 0;
+ return FALSE;
+}
+
+BOOL ScDocument::GetPrintAreaHor( SCTAB nTab, SCROW nStartRow, SCROW nEndRow,
+ SCCOL& rEndCol, BOOL bNotes ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ {
+ BOOL bAny = pTab[nTab]->GetPrintAreaHor( nStartRow, nEndRow, rEndCol, bNotes );
+ if (pDrawLayer)
+ {
+ ScRange aDrawRange(0,nStartRow,nTab, MAXCOL,nEndRow,nTab);
+ if (DrawGetPrintArea( aDrawRange, TRUE, FALSE ))
+ {
+ if (aDrawRange.aEnd.Col()>rEndCol) rEndCol=aDrawRange.aEnd.Col();
+ bAny = TRUE;
+ }
+ }
+ return bAny;
+ }
+
+ rEndCol = 0;
+ return FALSE;
+}
+
+BOOL ScDocument::GetPrintAreaVer( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol,
+ SCROW& rEndRow, BOOL bNotes ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ {
+ BOOL bAny = pTab[nTab]->GetPrintAreaVer( nStartCol, nEndCol, rEndRow, bNotes );
+ if (pDrawLayer)
+ {
+ ScRange aDrawRange(nStartCol,0,nTab, nEndCol,MAXROW,nTab);
+ if (DrawGetPrintArea( aDrawRange, FALSE, TRUE ))
+ {
+ if (aDrawRange.aEnd.Row()>rEndRow) rEndRow=aDrawRange.aEnd.Row();
+ bAny = TRUE;
+ }
+ }
+ return bAny;
+ }
+
+ rEndRow = 0;
+ return FALSE;
+}
+
+BOOL ScDocument::GetDataStart( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ {
+ BOOL bAny = pTab[nTab]->GetDataStart( rStartCol, rStartRow );
+ if (pDrawLayer)
+ {
+ ScRange aDrawRange(0,0,nTab, MAXCOL,MAXROW,nTab);
+ if (DrawGetPrintArea( aDrawRange, TRUE, TRUE ))
+ {
+ if (aDrawRange.aStart.Col()<rStartCol) rStartCol=aDrawRange.aStart.Col();
+ if (aDrawRange.aStart.Row()<rStartRow) rStartRow=aDrawRange.aStart.Row();
+ bAny = TRUE;
+ }
+ }
+ return bAny;
+ }
+
+ rStartCol = 0;
+ rStartRow = 0;
+ return FALSE;
+}
+
+BOOL ScDocument::MoveTab( SCTAB nOldPos, SCTAB nNewPos )
+{
+ if (nOldPos == nNewPos) return FALSE;
+ BOOL bValid = FALSE;
+ if (VALIDTAB(nOldPos))
+ {
+ if (pTab[nOldPos])
+ {
+ SCTAB nTabCount = GetTableCount();
+ if (nTabCount > 1)
+ {
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ SetNoListening( TRUE );
+ ScProgress* pProgress = new ScProgress( GetDocumentShell(),
+ ScGlobal::GetRscString(STR_UNDO_MOVE_TAB), GetCodeCount() );
+ if (nNewPos == SC_TAB_APPEND)
+ nNewPos = nTabCount-1;
+
+ // Referenz-Updaterei
+ //! mit UpdateReference zusammenfassen!
+
+ SCsTAB nDz = ((SCsTAB)nNewPos) - (SCsTAB)nOldPos;
+ ScRange aSourceRange( 0,0,nOldPos, MAXCOL,MAXROW,nOldPos );
+ pRangeName->UpdateTabRef(nOldPos, 3, nNewPos);
+ pDBCollection->UpdateMoveTab( nOldPos, nNewPos );
+ xColNameRanges->UpdateReference( URM_REORDER, this, aSourceRange, 0,0,nDz );
+ xRowNameRanges->UpdateReference( URM_REORDER, this, aSourceRange, 0,0,nDz );
+#if OLD_PIVOT_IMPLEMENTATION
+ if (pPivotCollection)
+ pPivotCollection->UpdateReference( URM_REORDER,
+ 0,0,nOldPos, MAXCOL,MAXROW,nOldPos, 0,0,nDz );
+#endif
+ if (pDPCollection)
+ pDPCollection->UpdateReference( URM_REORDER, aSourceRange, 0,0,nDz );
+ if (pDetOpList)
+ pDetOpList->UpdateReference( this, URM_REORDER, aSourceRange, 0,0,nDz );
+ UpdateChartRef( URM_REORDER,
+ 0,0,nOldPos, MAXCOL,MAXROW,nOldPos, 0,0,nDz );
+ UpdateRefAreaLinks( URM_REORDER, aSourceRange, 0,0,nDz );
+ if ( pCondFormList )
+ pCondFormList->UpdateMoveTab( nOldPos, nNewPos );
+ if ( pValidationList )
+ pValidationList->UpdateMoveTab( nOldPos, nNewPos );
+ if ( pUnoBroadcaster )
+ pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_REORDER,
+ aSourceRange, 0,0,nDz ) );
+
+ ScTable* pSaveTab = pTab[nOldPos];
+ SCTAB i;
+ for (i = nOldPos + 1; i < nTabCount; i++)
+ pTab[i - 1] = pTab[i];
+ pTab[i-1] = NULL;
+ for (i = nTabCount - 1; i > nNewPos; i--)
+ pTab[i] = pTab[i - 1];
+ pTab[nNewPos] = pSaveTab;
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateMoveTab( nOldPos, nNewPos, i, *pProgress );
+ delete pProgress; // freimachen fuer evtl. andere
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateCompile();
+ SetNoListening( FALSE );
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartAllListeners();
+ // #81844# sheet names of references may not be valid until sheet is moved
+ pChartListenerCollection->UpdateScheduledSeriesRanges();
+ SetDirty();
+ SetAutoCalc( bOldAutoCalc );
+
+ if (pDrawLayer)
+ DrawMovePage( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) );
+
+ // Update cells containing external references.
+ if (pExternalRefMgr.get())
+ pExternalRefMgr->updateRefMoveTable(nOldPos, nNewPos, false);
+
+ bValid = TRUE;
+ }
+ }
+ }
+ return bValid;
+}
+
+BOOL ScDocument::CopyTab( SCTAB nOldPos, SCTAB nNewPos, const ScMarkData* pOnlyMarked )
+{
+ if (SC_TAB_APPEND == nNewPos ) nNewPos = nMaxTableNumber;
+ String aName;
+ GetName(nOldPos, aName);
+
+ // vorneweg testen, ob der Prefix als gueltig erkannt wird
+ // wenn nicht, nur doppelte vermeiden
+ BOOL bPrefix = ValidTabName( aName );
+ DBG_ASSERT(bPrefix, "ungueltiger Tabellenname");
+ SCTAB nDummy;
+
+ CreateValidTabName(aName);
+
+ BOOL bValid;
+ if (bPrefix)
+ bValid = ( ValidNewTabName(aName) && (nMaxTableNumber <= MAXTAB) );
+ else
+ bValid = ( !GetTable( aName, nDummy ) && (nMaxTableNumber <= MAXTAB) );
+
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ if (bValid)
+ {
+ if (nNewPos == nMaxTableNumber)
+ {
+ pTab[nMaxTableNumber] = new ScTable(this, nMaxTableNumber, aName);
+ ++nMaxTableNumber;
+ }
+ else
+ {
+ if (VALIDTAB(nNewPos) && (nNewPos < nMaxTableNumber))
+ {
+ SetNoListening( TRUE );
+
+ ScRange aRange( 0,0,nNewPos, MAXCOL,MAXROW,MAXTAB );
+ xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
+ xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
+ pRangeName->UpdateTabRef(nNewPos, 1);
+ pDBCollection->UpdateReference(
+ URM_INSDEL, 0,0,nNewPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
+#if OLD_PIVOT_IMPLEMENTATION
+ if (pPivotCollection)
+ pPivotCollection->UpdateReference(
+ URM_INSDEL, 0,0,nNewPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
+#endif
+ if (pDPCollection)
+ pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
+ if (pDetOpList)
+ pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
+ UpdateChartRef( URM_INSDEL, 0,0,nNewPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
+ UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
+ if ( pUnoBroadcaster )
+ pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
+
+ SCTAB i;
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i] && i != nOldPos)
+ pTab[i]->UpdateInsertTab(nNewPos);
+ for (i = nMaxTableNumber; i > nNewPos; i--)
+ pTab[i] = pTab[i - 1];
+ if (nNewPos <= nOldPos)
+ nOldPos++;
+ pTab[nNewPos] = new ScTable(this, nNewPos, aName);
+ ++nMaxTableNumber;
+ bValid = TRUE;
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i] && i != nOldPos && i != nNewPos)
+ pTab[i]->UpdateCompile();
+ SetNoListening( FALSE );
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i] && i != nOldPos && i != nNewPos)
+ pTab[i]->StartAllListeners();
+
+ // update conditional formats after table is inserted
+ if ( pCondFormList )
+ pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
+ if ( pValidationList )
+ pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
+ // #81844# sheet names of references may not be valid until sheet is copied
+ pChartListenerCollection->UpdateScheduledSeriesRanges();
+ }
+ else
+ bValid = FALSE;
+ }
+ }
+ if (bValid)
+ {
+ SetNoListening( TRUE ); // noch nicht bei CopyToTable/Insert
+ pTab[nOldPos]->CopyToTable(0, 0, MAXCOL, MAXROW, IDF_ALL, (pOnlyMarked != NULL),
+ pTab[nNewPos], pOnlyMarked );
+ SCsTAB nDz;
+/* if (nNewPos < nOldPos)
+ nDz = ((short)nNewPos) - (short)nOldPos + 1;
+ else
+*/ nDz = ((short)nNewPos) - (short)nOldPos;
+ pTab[nNewPos]->UpdateReference(URM_COPY, 0, 0, nNewPos , MAXCOL, MAXROW,
+ nNewPos, 0, 0, nDz, NULL);
+
+ pTab[nNewPos]->UpdateInsertTabAbs(nNewPos); // alle abs. um eins hoch!!
+ pTab[nOldPos]->UpdateInsertTab(nNewPos);
+
+ pTab[nOldPos]->UpdateCompile();
+ pTab[nNewPos]->UpdateCompile( TRUE ); // #67996# maybe already compiled in Clone, but used names need recompilation
+ SetNoListening( FALSE );
+ pTab[nOldPos]->StartAllListeners();
+ pTab[nNewPos]->StartAllListeners();
+ SetDirty();
+ SetAutoCalc( bOldAutoCalc );
+
+ if (pDrawLayer)
+ DrawCopyPage( static_cast<sal_uInt16>(nOldPos), static_cast<sal_uInt16>(nNewPos) );
+
+ pTab[nNewPos]->SetPageStyle( pTab[nOldPos]->GetPageStyle() );
+
+ // Update cells containing external references.
+ if (pExternalRefMgr.get())
+ pExternalRefMgr->updateRefMoveTable(nOldPos, nNewPos, true);
+ }
+ else
+ SetAutoCalc( bOldAutoCalc );
+ return bValid;
+}
+
+ULONG ScDocument::TransferTab( ScDocument* pSrcDoc, SCTAB nSrcPos,
+ SCTAB nDestPos, BOOL bInsertNew,
+ BOOL bResultsOnly )
+{
+ ULONG nRetVal = 1; // 0 => Fehler 1 = ok
+ // 2 => RefBox, 3 => NameBox
+ // 4 => beides
+ BOOL bValid = TRUE;
+ if (bInsertNew) // neu einfuegen
+ {
+ String aName;
+ pSrcDoc->GetName(nSrcPos, aName);
+ CreateValidTabName(aName);
+ bValid = InsertTab(nDestPos, aName);
+ }
+ else // bestehende Tabelle ersetzen
+ {
+ if (VALIDTAB(nDestPos) && pTab[nDestPos])
+ {
+ pTab[nDestPos]->DeleteArea( 0,0, MAXCOL,MAXROW, IDF_ALL );
+ }
+ else
+ bValid = FALSE;
+ }
+
+ if (bValid)
+ {
+ BOOL bOldAutoCalcSrc = FALSE;
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ SetNoListening( TRUE );
+ if ( bResultsOnly )
+ {
+ bOldAutoCalcSrc = pSrcDoc->GetAutoCalc();
+ pSrcDoc->SetAutoCalc( TRUE ); // falls was berechnet werden muss
+ }
+ SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
+ SvNumberFormatter* pOtherFormatter = pSrcDoc->xPoolHelper->GetFormTable();
+ if (pOtherFormatter && pOtherFormatter != pThisFormatter)
+ {
+ SvNumberFormatterIndexTable* pExchangeList =
+ pThisFormatter->MergeFormatter(*(pOtherFormatter));
+ if (pExchangeList->Count() > 0)
+ pFormatExchangeList = pExchangeList;
+ }
+ nDestPos = Min(nDestPos, (SCTAB)(GetTableCount() - 1));
+ { // scope for bulk broadcast
+ ScBulkBroadcast aBulkBroadcast( pBASM);
+ pSrcDoc->pTab[nSrcPos]->CopyToTable(0, 0, MAXCOL, MAXROW,
+ ( bResultsOnly ? IDF_ALL & ~IDF_FORMULA : IDF_ALL),
+ FALSE, pTab[nDestPos] );
+ }
+ pFormatExchangeList = NULL;
+ pTab[nDestPos]->SetTabNo(nDestPos);
+
+ if ( !bResultsOnly )
+ {
+ BOOL bNamesLost = FALSE;
+ USHORT nSrcRangeNames = pSrcDoc->pRangeName->GetCount();
+ // array containing range names which might need update of indices
+ ScRangeData** pSrcRangeNames = nSrcRangeNames ? new ScRangeData* [nSrcRangeNames] : NULL;
+ // the index mapping thereof
+ ScIndexMap aSrcRangeMap( nSrcRangeNames );
+ BOOL bRangeNameReplace = FALSE;
+
+ // find named ranges that are used in the source sheet
+ std::set<USHORT> aUsedNames;
+ pSrcDoc->pTab[nSrcPos]->FindRangeNamesInUse( 0, 0, MAXCOL, MAXROW, aUsedNames );
+
+ for (USHORT i = 0; i < nSrcRangeNames; i++) //! DB-Bereiche Pivot-Bereiche auch !!!
+ {
+ ScRangeData* pSrcData = (*pSrcDoc->pRangeName)[i];
+ USHORT nOldIndex = pSrcData->GetIndex();
+ bool bInUse = ( aUsedNames.find(nOldIndex) != aUsedNames.end() );
+ if (bInUse)
+ {
+ USHORT nExisting = 0;
+ if ( pRangeName->SearchName( pSrcData->GetName(), nExisting ) )
+ {
+ // the name exists already in the destination document
+ // -> use the existing name, but show a warning
+ // (when refreshing links, the existing name is used and the warning not shown)
+
+ ScRangeData* pExistingData = (*pRangeName)[nExisting];
+ USHORT nExistingIndex = pExistingData->GetIndex();
+
+ pSrcRangeNames[i] = NULL; // don't modify the named range
+ aSrcRangeMap.SetPair( i, nOldIndex, nExistingIndex );
+ bRangeNameReplace = TRUE;
+ bNamesLost = TRUE;
+ }
+ else
+ {
+ ScRangeData* pData = new ScRangeData( *pSrcData );
+ pData->SetDocument(this);
+ if ( pRangeName->FindIndex( pData->GetIndex() ) )
+ pData->SetIndex(0); // need new index, done in Insert
+ if (!pRangeName->Insert(pData))
+ {
+ DBG_ERROR("can't insert name"); // shouldn't happen
+ delete pData;
+ }
+ else
+ {
+ pData->TransferTabRef( nSrcPos, nDestPos );
+ pSrcRangeNames[i] = pData;
+ USHORT nNewIndex = pData->GetIndex();
+ aSrcRangeMap.SetPair( i, nOldIndex, nNewIndex );
+ if ( !bRangeNameReplace )
+ bRangeNameReplace = ( nOldIndex != nNewIndex );
+ }
+ }
+ }
+ else
+ {
+ pSrcRangeNames[i] = NULL;
+ //aSrcRangeMap.SetPair( i, 0, 0 ); // not needed, defaulted
+ }
+ }
+ if ( bRangeNameReplace )
+ {
+ // first update all inserted named formulas if they contain other
+ // range names and used indices changed
+ for (USHORT i = 0; i < nSrcRangeNames; i++) //! DB-Bereiche Pivot-Bereiche auch
+ {
+ if ( pSrcRangeNames[i] )
+ pSrcRangeNames[i]->ReplaceRangeNamesInUse( aSrcRangeMap );
+ }
+ // then update the formulas, they might need the just updated range names
+ pTab[nDestPos]->ReplaceRangeNamesInUse( 0, 0, MAXCOL, MAXROW, aSrcRangeMap );
+ }
+ if ( pSrcRangeNames )
+ delete [] pSrcRangeNames;
+
+ SCsTAB nDz = ((SCsTAB)nDestPos) - (SCsTAB)nSrcPos;
+ pTab[nDestPos]->UpdateReference(URM_COPY, 0, 0, nDestPos,
+ MAXCOL, MAXROW, nDestPos,
+ 0, 0, nDz, NULL);
+ // Test for outside absolute references for info box
+ BOOL bIsAbsRef = pSrcDoc->pTab[nSrcPos]->TestTabRefAbs(nSrcPos);
+ // Readjust self-contained absolute references to this sheet
+ pTab[nDestPos]->TestTabRefAbs(nSrcPos);
+ if (bIsAbsRef)
+ {
+ nRetVal += 1;
+ // InfoBox AbsoluteRefs sind moeglicherweise nicht mehr korrekt!!
+ }
+ if (bNamesLost)
+ {
+ nRetVal += 2;
+ // message: duplicate names
+ }
+ pTab[nDestPos]->CompileAll();
+ }
+
+ SetNoListening( FALSE );
+ if ( !bResultsOnly )
+ pTab[nDestPos]->StartAllListeners();
+ SetDirty( ScRange( 0, 0, nDestPos, MAXCOL, MAXROW, nDestPos));
+
+ if ( bResultsOnly )
+ pSrcDoc->SetAutoCalc( bOldAutoCalcSrc );
+ SetAutoCalc( bOldAutoCalc );
+
+ // Drawing kopieren
+
+ if (bInsertNew)
+ TransferDrawPage( pSrcDoc, nSrcPos, nDestPos );
+ }
+ if (!bValid)
+ nRetVal = 0;
+ return nRetVal;
+}
+
+// ----------------------------------------------------------------------------
+
+void ScDocument::SetError( SCCOL nCol, SCROW nRow, SCTAB nTab, const USHORT nError)
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetError( nCol, nRow, nError );
+}
+
+void ScDocument::EraseNonUsedSharedNames(USHORT nLevel)
+{
+ for (USHORT i = 0; i < pRangeName->GetCount(); i++)
+ {
+ ScRangeData* pRangeData = (*pRangeName)[i];
+ if (pRangeData && pRangeData->HasType(RT_SHARED))
+ {
+ String aName;
+ pRangeData->GetName(aName);
+ aName.Erase(0, 6); // !!! vgl. Table4, FillFormula !!
+ USHORT nInd = (USHORT) aName.ToInt32();
+ if (nInd <= nLevel)
+ {
+ USHORT nIndex = pRangeData->GetIndex();
+ BOOL bInUse = FALSE;
+ for (SCTAB j = 0; !bInUse && (j <= MAXTAB); j++)
+ {
+ if (pTab[j])
+ bInUse = pTab[j]->IsRangeNameInUse(0, 0, MAXCOL-1, MAXROW-1,
+ nIndex);
+ }
+ if (!bInUse)
+ pRangeName->AtFree(i);
+ }
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+void ScDocument::SetConsolidateDlgData( const ScConsolidateParam* pData )
+{
+ delete pConsolidateDlgData;
+
+ if ( pData )
+ pConsolidateDlgData = new ScConsolidateParam( *pData );
+ else
+ pConsolidateDlgData = NULL;
+}
+
+void ScDocument::SetChangeViewSettings(const ScChangeViewSettings& rNew)
+{
+ if (pChangeViewSettings==NULL)
+ pChangeViewSettings = new ScChangeViewSettings;
+
+ DBG_ASSERT( pChangeViewSettings, "Oops. No ChangeViewSettings :-( by!" );
+
+ *pChangeViewSettings=rNew;
+}
+
+// ----------------------------------------------------------------------------
+
+ScFieldEditEngine* ScDocument::CreateFieldEditEngine()
+{
+ ScFieldEditEngine* pNewEditEngine = NULL;
+ if (!pCacheFieldEditEngine)
+ {
+ pNewEditEngine = new ScFieldEditEngine( GetEnginePool(),
+ GetEditPool(), FALSE );
+ }
+ else
+ {
+ if ( !bImportingXML )
+ {
+ // #i66209# previous use might not have restored update mode,
+ // ensure same state as for a new EditEngine (UpdateMode = TRUE)
+ if ( !pCacheFieldEditEngine->GetUpdateMode() )
+ pCacheFieldEditEngine->SetUpdateMode(TRUE);
+ }
+
+ pNewEditEngine = pCacheFieldEditEngine;
+ pCacheFieldEditEngine = NULL;
+ }
+ return pNewEditEngine;
+}
+
+void ScDocument::DisposeFieldEditEngine(ScFieldEditEngine*& rpEditEngine)
+{
+ if (!pCacheFieldEditEngine && rpEditEngine)
+ {
+ pCacheFieldEditEngine = rpEditEngine;
+ pCacheFieldEditEngine->Clear();
+ }
+ else
+ delete rpEditEngine;
+ rpEditEngine = NULL;
+}
+
+// ----------------------------------------------------------------------------
+
+// static
+ScRecursionHelper* ScDocument::CreateRecursionHelperInstance()
+{
+ return new ScRecursionHelper;
+}
+
+// ----------------------------------------------------------------------------
+
+ScLookupCache & ScDocument::GetLookupCache( const ScRange & rRange )
+{
+ ScLookupCache* pCache = 0;
+ if (!pLookupCacheMapImpl)
+ pLookupCacheMapImpl = new ScLookupCacheMapImpl;
+ ScLookupCacheMap::iterator it( pLookupCacheMapImpl->aCacheMap.find( rRange));
+ if (it == pLookupCacheMapImpl->aCacheMap.end())
+ {
+ pCache = new ScLookupCache( this, rRange);
+ AddLookupCache( *pCache);
+ }
+ else
+ pCache = (*it).second;
+ return *pCache;
+}
+
+void ScDocument::AddLookupCache( ScLookupCache & rCache )
+{
+ if (!pLookupCacheMapImpl->aCacheMap.insert( ::std::pair< const ScRange,
+ ScLookupCache*>( rCache.getRange(), &rCache)).second)
+ {
+ DBG_ERRORFILE( "ScDocument::AddLookupCache: couldn't add to hash map");
+ }
+ else
+ StartListeningArea( rCache.getRange(), &rCache);
+}
+
+void ScDocument::RemoveLookupCache( ScLookupCache & rCache )
+{
+ ScLookupCacheMap::iterator it( pLookupCacheMapImpl->aCacheMap.find(
+ rCache.getRange()));
+ if (it == pLookupCacheMapImpl->aCacheMap.end())
+ {
+ DBG_ERRORFILE( "ScDocument::RemoveLookupCache: range not found in hash map");
+ }
+ else
+ {
+ ScLookupCache* pCache = (*it).second;
+ pLookupCacheMapImpl->aCacheMap.erase( it);
+ EndListeningArea( pCache->getRange(), &rCache);
+ }
+}
+
+void ScDocument::ClearLookupCaches()
+{
+ if( pLookupCacheMapImpl )
+ pLookupCacheMapImpl->clear();
+}
diff --git a/sc/source/core/data/documen3.cxx b/sc/source/core/data/documen3.cxx
new file mode 100644
index 000000000000..2b3fbb359988
--- /dev/null
+++ b/sc/source/core/data/documen3.cxx
@@ -0,0 +1,1937 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: documen3.cxx,v $
+ * $Revision: 1.42.100.5 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/langitem.hxx>
+#include <svx/srchitem.hxx>
+#include <svx/linkmgr.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/objsh.hxx>
+#include <svtools/zforlist.hxx>
+#include <vcl/svapp.hxx>
+#include "document.hxx"
+#include "attrib.hxx"
+#include "cell.hxx"
+#include "table.hxx"
+#include "rangenam.hxx"
+#include "dbcolect.hxx"
+#include "pivot.hxx"
+#include "docpool.hxx"
+#include "poolhelp.hxx"
+#include "autoform.hxx"
+#include "rangelst.hxx"
+#include "chartarr.hxx"
+#include "chartlock.hxx"
+#include "refupdat.hxx"
+#include "docoptio.hxx"
+#include "viewopti.hxx"
+#include "scextopt.hxx"
+#include "brdcst.hxx"
+#include "bcaslot.hxx"
+#include "tablink.hxx"
+#include "externalrefmgr.hxx"
+#include "markdata.hxx"
+#include "validat.hxx"
+#include "dociter.hxx"
+#include "detdata.hxx"
+#include "detfunc.hxx"
+#include "scmod.hxx" // SC_MOD
+#include "inputopt.hxx" // GetExpandRefs
+#include "chartlis.hxx"
+#include "sc.hrc" // SID_LINK
+#include "hints.hxx"
+#include "dpobject.hxx"
+#include "unoguard.hxx"
+#include "drwlayer.hxx"
+#include "unoreflist.hxx"
+#include "listenercalls.hxx"
+
+#include <memory>
+
+using namespace com::sun::star;
+using ::std::auto_ptr;
+
+//------------------------------------------------------------------------
+
+ScRangeName* ScDocument::GetRangeName()
+{
+ return pRangeName;
+}
+
+void ScDocument::SetRangeName( ScRangeName* pNewRangeName )
+{
+ if (pRangeName)
+ delete pRangeName;
+ pRangeName = pNewRangeName;
+}
+
+//UNUSED2008-05 ScRangeData* ScDocument::GetRangeAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab,
+//UNUSED2008-05 BOOL bStartOnly) const
+//UNUSED2008-05 {
+//UNUSED2008-05 if ( pRangeName )
+//UNUSED2008-05 return pRangeName->GetRangeAtCursor( ScAddress( nCol, nRow, nTab ), bStartOnly );
+//UNUSED2008-05 else
+//UNUSED2008-05 return NULL;
+//UNUSED2008-05 }
+
+ScRangeData* ScDocument::GetRangeAtBlock( const ScRange& rBlock, String* pName ) const
+{
+ ScRangeData* pData = NULL;
+ if ( pRangeName )
+ {
+ pData = pRangeName->GetRangeAtBlock( rBlock );
+ if (pData && pName)
+ *pName = pData->GetName();
+ }
+ return pData;
+}
+
+ScDBCollection* ScDocument::GetDBCollection() const
+{
+ return pDBCollection;
+}
+
+void ScDocument::SetDBCollection( ScDBCollection* pNewDBCollection, BOOL bRemoveAutoFilter )
+{
+ if ( bRemoveAutoFilter )
+ {
+ // remove auto filter attribute if new db data don't contain auto filter flag
+ // start position is also compared, so bRemoveAutoFilter must not be set from ref-undo!
+
+ if ( pDBCollection )
+ {
+ USHORT nOldCount = pDBCollection->GetCount();
+ for (USHORT nOld=0; nOld<nOldCount; nOld++)
+ {
+ ScDBData* pOldData = (*pDBCollection)[nOld];
+ if ( pOldData->HasAutoFilter() )
+ {
+ ScRange aOldRange;
+ pOldData->GetArea( aOldRange );
+
+ BOOL bFound = FALSE;
+ USHORT nNewIndex = 0;
+ if ( pNewDBCollection &&
+ pNewDBCollection->SearchName( pOldData->GetName(), nNewIndex ) )
+ {
+ ScDBData* pNewData = (*pNewDBCollection)[nNewIndex];
+ if ( pNewData->HasAutoFilter() )
+ {
+ ScRange aNewRange;
+ pNewData->GetArea( aNewRange );
+ if ( aOldRange.aStart == aNewRange.aStart )
+ bFound = TRUE;
+ }
+ }
+
+ if ( !bFound )
+ {
+ aOldRange.aEnd.SetRow( aOldRange.aStart.Row() );
+ RemoveFlagsTab( aOldRange.aStart.Col(), aOldRange.aStart.Row(),
+ aOldRange.aEnd.Col(), aOldRange.aEnd.Row(),
+ aOldRange.aStart.Tab(), SC_MF_AUTO );
+ if (pShell)
+ pShell->Broadcast( ScPaintHint( aOldRange, PAINT_GRID ) );
+ }
+ }
+ }
+ }
+ }
+
+ if (pDBCollection)
+ delete pDBCollection;
+ pDBCollection = pNewDBCollection;
+}
+
+ScDBData* ScDocument::GetDBAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, BOOL bStartOnly) const
+{
+ if (pDBCollection)
+ return pDBCollection->GetDBAtCursor(nCol, nRow, nTab, bStartOnly);
+ else
+ return NULL;
+}
+
+ScDBData* ScDocument::GetDBAtArea(SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
+{
+ if (pDBCollection)
+ return pDBCollection->GetDBAtArea(nTab, nCol1, nRow1, nCol2, nRow2);
+ else
+ return NULL;
+}
+
+ScDPCollection* ScDocument::GetDPCollection()
+{
+ if (!pDPCollection)
+ pDPCollection = new ScDPCollection(this);
+ return pDPCollection;
+}
+
+ScDPObject* ScDocument::GetDPAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
+{
+ if (!pDPCollection)
+ return NULL;
+
+ USHORT nCount = pDPCollection->GetCount();
+ ScAddress aPos( nCol, nRow, nTab );
+ for (USHORT i=0; i<nCount; i++)
+ if ( (*pDPCollection)[i]->GetOutRange().In( aPos ) )
+ return (*pDPCollection)[i];
+
+ return NULL;
+}
+
+ScDPObject* ScDocument::GetDPAtBlock( const ScRange & rBlock ) const
+{
+ if (!pDPCollection)
+ return NULL;
+
+ /* Walk the collection in reverse order to get something of an
+ * approximation of MS Excels 'most recent' effect. */
+ USHORT i = pDPCollection->GetCount();
+ while ( i-- > 0 )
+ if ( (*pDPCollection)[i]->GetOutRange().In( rBlock ) )
+ return (*pDPCollection)[i];
+
+ return NULL;
+}
+
+#if OLD_PIVOT_IMPLEMENTATION
+ScPivotCollection* ScDocument::GetPivotCollection() const
+{
+ return pPivotCollection;
+}
+
+void ScDocument::SetPivotCollection(ScPivotCollection* pNewPivotCollection)
+{
+ if ( pPivotCollection && pNewPivotCollection &&
+ *pPivotCollection == *pNewPivotCollection )
+ {
+ delete pNewPivotCollection;
+ return;
+ }
+
+ if (pPivotCollection)
+ delete pPivotCollection;
+ pPivotCollection = pNewPivotCollection;
+
+ if (pPivotCollection)
+ {
+ USHORT nCount = pPivotCollection->GetCount();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ScPivot* pPivot = (*pPivotCollection)[i];
+ if (pPivot->CreateData())
+ pPivot->ReleaseData();
+ }
+ }
+}
+
+ScPivot* ScDocument::GetPivotAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
+{
+ if (pPivotCollection)
+ return pPivotCollection->GetPivotAtCursor(nCol, nRow, nTab);
+ else
+ return NULL;
+}
+#endif
+
+ScChartCollection* ScDocument::GetChartCollection() const
+{
+ return pChartCollection;
+}
+
+void ScDocument::StopTemporaryChartLock()
+{
+ if( apTemporaryChartLock.get() )
+ apTemporaryChartLock->StopLocking();
+}
+
+void ScDocument::SetChartListenerCollection(
+ ScChartListenerCollection* pNewChartListenerCollection,
+ BOOL bSetChartRangeLists )
+{
+ ScChartListenerCollection* pOld = pChartListenerCollection;
+ pChartListenerCollection = pNewChartListenerCollection;
+ if ( pChartListenerCollection )
+ {
+ if ( pOld )
+ pChartListenerCollection->SetDiffDirty( *pOld, bSetChartRangeLists );
+ pChartListenerCollection->StartAllListeners();
+ }
+ delete pOld;
+}
+
+void ScDocument::SetScenario( SCTAB nTab, BOOL bFlag )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetScenario(bFlag);
+}
+
+BOOL ScDocument::IsScenario( SCTAB nTab ) const
+{
+ return ValidTab(nTab) && pTab[nTab] &&pTab[nTab]->IsScenario();
+ //if (ValidTab(nTab) && pTab[nTab])
+ // return pTab[nTab]->IsScenario();
+
+ //return FALSE;
+}
+
+void ScDocument::SetScenarioData( SCTAB nTab, const String& rComment,
+ const Color& rColor, USHORT nFlags )
+{
+ if (ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
+ {
+ pTab[nTab]->SetScenarioComment( rComment );
+ pTab[nTab]->SetScenarioColor( rColor );
+ pTab[nTab]->SetScenarioFlags( nFlags );
+ }
+}
+
+void ScDocument::GetScenarioData( SCTAB nTab, String& rComment,
+ Color& rColor, USHORT& rFlags ) const
+{
+ if (ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
+ {
+ pTab[nTab]->GetScenarioComment( rComment );
+ rColor = pTab[nTab]->GetScenarioColor();
+ rFlags = pTab[nTab]->GetScenarioFlags();
+ }
+}
+
+void ScDocument::GetScenarioFlags( SCTAB nTab, USHORT& rFlags ) const
+{
+ if (VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->IsScenario())
+ rFlags = pTab[nTab]->GetScenarioFlags();
+}
+
+BOOL ScDocument::IsLinked( SCTAB nTab ) const
+{
+ return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsLinked();
+ // euqivalent to
+ //if (ValidTab(nTab) && pTab[nTab])
+ // return pTab[nTab]->IsLinked();
+ //return FALSE;
+}
+
+formula::FormulaGrammar::AddressConvention ScDocument::GetAddressConvention() const
+{
+ return formula::FormulaGrammar::extractRefConvention(eGrammar);
+}
+
+formula::FormulaGrammar::Grammar ScDocument::GetGrammar() const
+{
+ return eGrammar;
+}
+
+void ScDocument::SetGrammar( formula::FormulaGrammar::Grammar eGram )
+{
+ eGrammar = eGram;
+}
+
+BOOL ScDocument::GetLinkMode( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetLinkMode();
+ return SC_LINK_NONE;
+}
+
+const String& ScDocument::GetLinkDoc( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetLinkDoc();
+ return EMPTY_STRING;
+}
+
+const String& ScDocument::GetLinkFlt( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetLinkFlt();
+ return EMPTY_STRING;
+}
+
+const String& ScDocument::GetLinkOpt( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetLinkOpt();
+ return EMPTY_STRING;
+}
+
+const String& ScDocument::GetLinkTab( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetLinkTab();
+ return EMPTY_STRING;
+}
+
+ULONG ScDocument::GetLinkRefreshDelay( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetLinkRefreshDelay();
+ return 0;
+}
+
+void ScDocument::SetLink( SCTAB nTab, BYTE nMode, const String& rDoc,
+ const String& rFilter, const String& rOptions,
+ const String& rTabName, ULONG nRefreshDelay )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetLink( nMode, rDoc, rFilter, rOptions, rTabName, nRefreshDelay );
+}
+
+BOOL ScDocument::HasLink( const String& rDoc,
+ const String& rFilter, const String& rOptions ) const
+{
+ SCTAB nCount = GetTableCount();
+ for (SCTAB i=0; i<nCount; i++)
+ if (pTab[i]->IsLinked()
+ && pTab[i]->GetLinkDoc() == rDoc
+ && pTab[i]->GetLinkFlt() == rFilter
+ && pTab[i]->GetLinkOpt() == rOptions)
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL ScDocument::LinkExternalTab( SCTAB& rTab, const String& aDocTab,
+ const String& aFileName, const String& aTabName )
+{
+ if ( IsClipboard() )
+ {
+ DBG_ERRORFILE( "LinkExternalTab in Clipboard" );
+ return FALSE;
+ }
+ rTab = 0;
+ String aFilterName; // wird vom Loader gefuellt
+ String aOptions; // Filter-Optionen
+ sal_uInt32 nLinkCnt = pExtDocOptions ? pExtDocOptions->GetDocSettings().mnLinkCnt : 0;
+ ScDocumentLoader aLoader( aFileName, aFilterName, aOptions, nLinkCnt + 1 );
+ if ( aLoader.IsError() )
+ return FALSE;
+ ScDocument* pSrcDoc = aLoader.GetDocument();
+
+ // Tabelle kopieren
+ SCTAB nSrcTab;
+ if ( pSrcDoc->GetTable( aTabName, nSrcTab ) )
+ {
+ if ( !InsertTab( SC_TAB_APPEND, aDocTab, TRUE ) )
+ {
+ DBG_ERRORFILE("can't insert external document table");
+ return FALSE;
+ }
+ rTab = GetTableCount() - 1;
+ // nicht neu einfuegen, nur Ergebnisse
+ TransferTab( pSrcDoc, nSrcTab, rTab, FALSE, TRUE );
+ }
+ else
+ return FALSE;
+
+ ULONG nRefreshDelay = 0;
+
+ BOOL bWasThere = HasLink( aFileName, aFilterName, aOptions );
+ SetLink( rTab, SC_LINK_VALUE, aFileName, aFilterName, aOptions, aTabName, nRefreshDelay );
+ if ( !bWasThere ) // Link pro Quelldokument nur einmal eintragen
+ {
+ ScTableLink* pLink = new ScTableLink( pShell, aFileName, aFilterName, aOptions, nRefreshDelay );
+ pLink->SetInCreate( TRUE );
+ pLinkManager->InsertFileLink( *pLink, OBJECT_CLIENT_FILE, aFileName,
+ &aFilterName );
+ pLink->Update();
+ pLink->SetInCreate( FALSE );
+ SfxBindings* pBindings = GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_LINKS );
+ }
+ return TRUE;
+}
+
+ScExternalRefManager* ScDocument::GetExternalRefManager()
+{
+ if (!pExternalRefMgr.get())
+ pExternalRefMgr.reset(new ScExternalRefManager(this));
+
+ return pExternalRefMgr.get();
+}
+
+bool ScDocument::IsInExternalReferenceMarking() const
+{
+ return pExternalRefMgr.get() && pExternalRefMgr->isInReferenceMarking();
+}
+
+void ScDocument::MarkUsedExternalReferences()
+{
+ if (!pExternalRefMgr.get())
+ return;
+ if (!pExternalRefMgr->hasExternalData())
+ return;
+ // Charts.
+ bool bAllMarked = pExternalRefMgr->markUsedByLinkListeners();
+ // Formula cells.
+ for (SCTAB nTab = 0; !bAllMarked && nTab < nMaxTableNumber; ++nTab)
+ {
+ if (pTab[nTab])
+ bAllMarked = pTab[nTab]->MarkUsedExternalReferences();
+ }
+ /* NOTE: Conditional formats and validation objects are marked when
+ * collecting them during export. */
+}
+
+ScOutlineTable* ScDocument::GetOutlineTable( SCTAB nTab, BOOL bCreate )
+{
+ ScOutlineTable* pVal = NULL;
+
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ {
+ pVal = pTab[nTab]->GetOutlineTable();
+ if (!pVal)
+ if (bCreate)
+ {
+ pTab[nTab]->StartOutlineTable();
+ pVal = pTab[nTab]->GetOutlineTable();
+ }
+ }
+
+ return pVal;
+}
+
+BOOL ScDocument::SetOutlineTable( SCTAB nTab, const ScOutlineTable* pNewOutline )
+{
+ return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->SetOutlineTable(pNewOutline);
+ //if (VALIDTAB(nTab))
+ // if (pTab[nTab])
+ // return pTab[nTab]->SetOutlineTable(pNewOutline);
+
+ //return FALSE;
+}
+
+void ScDocument::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
+{
+ if (VALIDTAB(nTab) && pTab[nTab])
+ pTab[nTab]->DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
+}
+
+BOOL ScDocument::TestRemoveSubTotals( SCTAB nTab, const ScSubTotalParam& rParam )
+{
+ return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->TestRemoveSubTotals( rParam );
+ //if (VALIDTAB(nTab) && pTab[nTab] )
+ // return pTab[nTab]->TestRemoveSubTotals( rParam );
+
+ //return FALSE;
+}
+
+void ScDocument::RemoveSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ pTab[nTab]->RemoveSubTotals( rParam );
+}
+
+BOOL ScDocument::DoSubTotals( SCTAB nTab, ScSubTotalParam& rParam )
+{
+ return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->DoSubTotals( rParam );
+ //if (VALIDTAB(nTab))
+ // if (pTab[nTab])
+ // return pTab[nTab]->DoSubTotals( rParam );
+
+ //return FALSE;
+}
+
+BOOL ScDocument::HasSubTotalCells( const ScRange& rRange )
+{
+ ScCellIterator aIter( this, rRange );
+ ScBaseCell* pCell = aIter.GetFirst();
+ while (pCell)
+ {
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell)->IsSubTotal() )
+ return TRUE;
+
+ pCell = aIter.GetNext();
+ }
+ return FALSE; // none found
+}
+
+// kopiert aus diesem Dokument die Zellen von Positionen, an denen in pPosDoc
+// auch Zellen stehen, nach pDestDoc
+
+void ScDocument::CopyUpdated( ScDocument* pPosDoc, ScDocument* pDestDoc )
+{
+ SCTAB nCount = GetTableCount();
+ for (SCTAB nTab=0; nTab<nCount; nTab++)
+ if (pTab[nTab] && pPosDoc->pTab[nTab] && pDestDoc->pTab[nTab])
+ pTab[nTab]->CopyUpdated( pPosDoc->pTab[nTab], pDestDoc->pTab[nTab] );
+}
+
+void ScDocument::CopyScenario( SCTAB nSrcTab, SCTAB nDestTab, BOOL bNewScenario )
+{
+ if (ValidTab(nSrcTab) && ValidTab(nDestTab) && pTab[nSrcTab] && pTab[nDestTab])
+ {
+ // Flags fuer aktive Szenarios richtig setzen
+ // und aktuelle Werte in bisher aktive Szenarios zurueckschreiben
+
+ ScRangeList aRanges = *pTab[nSrcTab]->GetScenarioRanges();
+ const ULONG nRangeCount = aRanges.Count();
+
+ // nDestTab ist die Zieltabelle
+ for ( SCTAB nTab = nDestTab+1;
+ nTab<=MAXTAB && pTab[nTab] && pTab[nTab]->IsScenario();
+ nTab++ )
+ {
+ if ( pTab[nTab]->IsActiveScenario() ) // auch wenn's dasselbe Szenario ist
+ {
+ BOOL bTouched = FALSE;
+ for ( ULONG nR=0; nR<nRangeCount && !bTouched; nR++)
+ {
+ const ScRange* pRange = aRanges.GetObject(nR);
+ if ( pTab[nTab]->HasScenarioRange( *pRange ) )
+ bTouched = TRUE;
+ }
+ if (bTouched)
+ {
+ pTab[nTab]->SetActiveScenario(FALSE);
+ if ( pTab[nTab]->GetScenarioFlags() & SC_SCENARIO_TWOWAY )
+ pTab[nTab]->CopyScenarioFrom( pTab[nDestTab] );
+ }
+ }
+ }
+
+ pTab[nSrcTab]->SetActiveScenario(TRUE); // da kommt's her...
+ if (!bNewScenario) // Daten aus dem ausgewaehlten Szenario kopieren
+ {
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ pTab[nSrcTab]->CopyScenarioTo( pTab[nDestTab] );
+ SetDirty();
+ SetAutoCalc( bOldAutoCalc );
+ }
+ }
+}
+
+void ScDocument::MarkScenario( SCTAB nSrcTab, SCTAB nDestTab, ScMarkData& rDestMark,
+ BOOL bResetMark, USHORT nNeededBits ) const
+{
+ if (bResetMark)
+ rDestMark.ResetMark();
+
+ if (ValidTab(nSrcTab) && pTab[nSrcTab])
+ pTab[nSrcTab]->MarkScenarioIn( rDestMark, nNeededBits );
+
+ rDestMark.SetAreaTab( nDestTab );
+}
+
+BOOL ScDocument::HasScenarioRange( SCTAB nTab, const ScRange& rRange ) const
+{
+ return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->HasScenarioRange( rRange );
+ //if (ValidTab(nTab) && pTab[nTab])
+ // return pTab[nTab]->HasScenarioRange( rRange );
+
+ //return FALSE;
+}
+
+const ScRangeList* ScDocument::GetScenarioRanges( SCTAB nTab ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetScenarioRanges();
+
+ return NULL;
+}
+
+BOOL ScDocument::IsActiveScenario( SCTAB nTab ) const
+{
+ return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->IsActiveScenario( );
+ //if (ValidTab(nTab) && pTab[nTab])
+ // return pTab[nTab]->IsActiveScenario();
+
+ //return FALSE;
+}
+
+void ScDocument::SetActiveScenario( SCTAB nTab, BOOL bActive )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetActiveScenario( bActive );
+}
+
+BOOL ScDocument::TestCopyScenario( SCTAB nSrcTab, SCTAB nDestTab ) const
+{
+ if (ValidTab(nSrcTab) && ValidTab(nDestTab))
+ return pTab[nSrcTab]->TestCopyScenarioTo( pTab[nDestTab] );
+
+ DBG_ERROR("falsche Tabelle bei TestCopyScenario");
+ return FALSE;
+}
+
+void ScDocument::AddUnoObject( SfxListener& rObject )
+{
+ if (!pUnoBroadcaster)
+ pUnoBroadcaster = new SfxBroadcaster;
+
+ rObject.StartListening( *pUnoBroadcaster );
+}
+
+void ScDocument::RemoveUnoObject( SfxListener& rObject )
+{
+ if (pUnoBroadcaster)
+ {
+ rObject.EndListening( *pUnoBroadcaster );
+
+ if ( bInUnoBroadcast )
+ {
+ // #107294# Broadcasts from ScDocument::BroadcastUno are the only way that
+ // uno object methods are called without holding a reference.
+ //
+ // If RemoveUnoObject is called from an object dtor in the finalizer thread
+ // while the main thread is calling BroadcastUno, the dtor thread must wait
+ // (or the object's Notify might try to access a deleted object).
+ // The SolarMutex can't be locked here because if a component is called from
+ // a VCL event, the main thread has the SolarMutex locked all the time.
+ //
+ // This check is done after calling EndListening, so a later BroadcastUno call
+ // won't touch this object.
+
+ vos::IMutex& rSolarMutex = Application::GetSolarMutex();
+ if ( rSolarMutex.tryToAcquire() )
+ {
+ // BroadcastUno is always called with the SolarMutex locked, so if it
+ // can be acquired, this is within the same thread (should not happen)
+ DBG_ERRORFILE( "RemoveUnoObject called from BroadcastUno" );
+ rSolarMutex.release();
+ }
+ else
+ {
+ // let the thread that called BroadcastUno continue
+ while ( bInUnoBroadcast )
+ {
+ vos::OThread::yield();
+ }
+ }
+ }
+ }
+ else
+ {
+ DBG_ERROR("No Uno broadcaster");
+ }
+}
+
+void ScDocument::BroadcastUno( const SfxHint &rHint )
+{
+ if (pUnoBroadcaster)
+ {
+ bInUnoBroadcast = TRUE;
+ pUnoBroadcaster->Broadcast( rHint );
+ bInUnoBroadcast = FALSE;
+
+ // During Broadcast notification, Uno objects can add to pUnoListenerCalls.
+ // The listener calls must be processed after completing the broadcast,
+ // because they can add or remove objects from pUnoBroadcaster.
+
+ if ( pUnoListenerCalls && rHint.ISA( SfxSimpleHint ) &&
+ ((const SfxSimpleHint&)rHint).GetId() == SFX_HINT_DATACHANGED &&
+ !bInUnoListenerCall )
+ {
+ // Listener calls may lead to BroadcastUno calls again. The listener calls
+ // are not nested, instead the calls are collected in the list, and the
+ // outermost call executes them all.
+
+ ScChartLockGuard aChartLockGuard(this);
+ bInUnoListenerCall = TRUE;
+ pUnoListenerCalls->ExecuteAndClear();
+ bInUnoListenerCall = FALSE;
+ }
+ }
+}
+
+void ScDocument::AddUnoListenerCall( const uno::Reference<util::XModifyListener>& rListener,
+ const lang::EventObject& rEvent )
+{
+ DBG_ASSERT( bInUnoBroadcast, "AddUnoListenerCall is supposed to be called from BroadcastUno only" );
+
+ if ( !pUnoListenerCalls )
+ pUnoListenerCalls = new ScUnoListenerCalls;
+ pUnoListenerCalls->Add( rListener, rEvent );
+}
+
+void ScDocument::BeginUnoRefUndo()
+{
+ DBG_ASSERT( !pUnoRefUndoList, "BeginUnoRefUndo twice" );
+ delete pUnoRefUndoList;
+
+ pUnoRefUndoList = new ScUnoRefList;
+}
+
+ScUnoRefList* ScDocument::EndUnoRefUndo()
+{
+ ScUnoRefList* pRet = pUnoRefUndoList;
+ pUnoRefUndoList = NULL;
+ return pRet; // must be deleted by caller!
+}
+
+void ScDocument::AddUnoRefChange( sal_Int64 nId, const ScRangeList& rOldRanges )
+{
+ if ( pUnoRefUndoList )
+ pUnoRefUndoList->Add( nId, rOldRanges );
+}
+
+sal_Int64 ScDocument::GetNewUnoId()
+{
+ return ++nUnoObjectId;
+}
+
+void ScDocument::UpdateReference( UpdateRefMode eUpdateRefMode,
+ SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ ScDocument* pUndoDoc, BOOL bIncludeDraw )
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ PutInOrder( nTab1, nTab2 );
+ if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
+ {
+ BOOL bExpandRefsOld = IsExpandRefs();
+ if ( eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0 || nDz > 0) )
+ SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
+ SCTAB i;
+ SCTAB iMax;
+ if ( eUpdateRefMode == URM_COPY )
+ {
+ i = nTab1;
+ iMax = nTab2;
+ }
+ else
+ {
+ ScRange aRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ xColNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
+ xRowNameRanges->UpdateReference( eUpdateRefMode, this, aRange, nDx, nDy, nDz );
+ pDBCollection->UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
+ pRangeName->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
+#if OLD_PIVOT_IMPLEMENTATION
+ if (pPivotCollection)
+ pPivotCollection->UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
+#endif
+ if ( pDPCollection )
+ pDPCollection->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
+ UpdateChartRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
+ UpdateRefAreaLinks( eUpdateRefMode, aRange, nDx, nDy, nDz );
+ if ( pCondFormList )
+ pCondFormList->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
+ if ( pValidationList )
+ pValidationList->UpdateReference( eUpdateRefMode, aRange, nDx, nDy, nDz );
+ if ( pDetOpList )
+ pDetOpList->UpdateReference( this, eUpdateRefMode, aRange, nDx, nDy, nDz );
+ if ( pUnoBroadcaster )
+ pUnoBroadcaster->Broadcast( ScUpdateRefHint(
+ eUpdateRefMode, aRange, nDx, nDy, nDz ) );
+ i = 0;
+ iMax = MAXTAB;
+ }
+ for ( ; i<=iMax; i++)
+ if (pTab[i])
+ pTab[i]->UpdateReference(
+ eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
+ nDx, nDy, nDz, pUndoDoc, bIncludeDraw );
+
+ if ( bIsEmbedded )
+ {
+ SCCOL theCol1;
+ SCROW theRow1;
+ SCTAB theTab1;
+ SCCOL theCol2;
+ SCROW theRow2;
+ SCTAB theTab2;
+ theCol1 = aEmbedRange.aStart.Col();
+ theRow1 = aEmbedRange.aStart.Row();
+ theTab1 = aEmbedRange.aStart.Tab();
+ theCol2 = aEmbedRange.aEnd.Col();
+ theRow2 = aEmbedRange.aEnd.Row();
+ theTab2 = aEmbedRange.aEnd.Tab();
+ if ( ScRefUpdate::Update( this, eUpdateRefMode, nCol1,nRow1,nTab1, nCol2,nRow2,nTab2,
+ nDx,nDy,nDz, theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 ) )
+ {
+ aEmbedRange = ScRange( theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
+ }
+ }
+ SetExpandRefs( bExpandRefsOld );
+
+ // #30428# after moving, no clipboard move ref-updates are possible
+ if ( eUpdateRefMode != URM_COPY && IsClipboardSource() )
+ {
+ ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
+ if (pClipDoc)
+ pClipDoc->bCutMode = FALSE;
+ }
+ }
+}
+
+void ScDocument::UpdateTranspose( const ScAddress& rDestPos, ScDocument* pClipDoc,
+ const ScMarkData& rMark, ScDocument* pUndoDoc )
+{
+ DBG_ASSERT(pClipDoc->bIsClip, "UpdateTranspose: kein Clip");
+
+ ScRange aSource = pClipDoc->aClipRange; // Tab wird noch angepasst
+ ScAddress aDest = rDestPos;
+
+ SCTAB nClipTab = 0;
+ for (SCTAB nDestTab=0; nDestTab<=MAXTAB && pTab[nDestTab]; nDestTab++)
+ if (rMark.GetTableSelect(nDestTab))
+ {
+ while (!pClipDoc->pTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
+ aSource.aStart.SetTab( nClipTab );
+ aSource.aEnd.SetTab( nClipTab );
+ aDest.SetTab( nDestTab );
+
+ // wie UpdateReference
+
+ pRangeName->UpdateTranspose( aSource, aDest ); // vor den Zellen!
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateTranspose( aSource, aDest, pUndoDoc );
+
+ nClipTab = (nClipTab+1) % (MAXTAB+1);
+ }
+}
+
+void ScDocument::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
+{
+ //! pDBCollection
+ //! pPivotCollection
+ //! UpdateChartRef
+
+ pRangeName->UpdateGrow( rArea, nGrowX, nGrowY );
+#if OLD_PIVOT_IMPLEMENTATION
+ pPivotCollection->UpdateGrow( rArea, nGrowX, nGrowY );
+#endif
+
+ for (SCTAB i=0; i<=MAXTAB && pTab[i]; i++)
+ pTab[i]->UpdateGrow( rArea, nGrowX, nGrowY );
+}
+
+void ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData& rMark,
+ ULONG nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
+ double nStepValue, double nMaxValue)
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ for (SCTAB i=0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->Fill(nCol1, nRow1, nCol2, nRow2,
+ nFillCount, eFillDir, eFillCmd, eFillDateCmd,
+ nStepValue, nMaxValue);
+}
+
+String ScDocument::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
+{
+ SCTAB nTab = rSource.aStart.Tab();
+ if (pTab[nTab])
+ return pTab[nTab]->GetAutoFillPreview( rSource, nEndX, nEndY );
+
+ return EMPTY_STRING;
+}
+
+void ScDocument::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ USHORT nFormatNo, const ScMarkData& rMark )
+{
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartRow, nEndRow );
+ for (SCTAB i=0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo );
+}
+
+void ScDocument::GetAutoFormatData(SCTAB nTab, SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ ScAutoFormatData& rData)
+{
+ if (VALIDTAB(nTab))
+ {
+ if (pTab[nTab])
+ {
+ PutInOrder(nStartCol, nEndCol);
+ PutInOrder(nStartRow, nEndRow);
+ pTab[nTab]->GetAutoFormatData(nStartCol, nStartRow, nEndCol, nEndRow, rData);
+ }
+ }
+}
+
+// static
+void ScDocument::GetSearchAndReplaceStart( const SvxSearchItem& rSearchItem,
+ SCCOL& rCol, SCROW& rRow )
+{
+ USHORT nCommand = rSearchItem.GetCommand();
+ BOOL bReplace = ( nCommand == SVX_SEARCHCMD_REPLACE ||
+ nCommand == SVX_SEARCHCMD_REPLACE_ALL );
+ if ( rSearchItem.GetBackward() )
+ {
+ if ( rSearchItem.GetRowDirection() )
+ {
+ if ( rSearchItem.GetPattern() )
+ {
+ rCol = MAXCOL;
+ rRow = MAXROW+1;
+ }
+ else if ( bReplace )
+ {
+ rCol = MAXCOL;
+ rRow = MAXROW;
+ }
+ else
+ {
+ rCol = MAXCOL+1;
+ rRow = MAXROW;
+ }
+ }
+ else
+ {
+ if ( rSearchItem.GetPattern() )
+ {
+ rCol = MAXCOL+1;
+ rRow = MAXROW;
+ }
+ else if ( bReplace )
+ {
+ rCol = MAXCOL;
+ rRow = MAXROW;
+ }
+ else
+ {
+ rCol = MAXCOL;
+ rRow = MAXROW+1;
+ }
+ }
+ }
+ else
+ {
+ if ( rSearchItem.GetRowDirection() )
+ {
+ if ( rSearchItem.GetPattern() )
+ {
+ rCol = 0;
+ rRow = (SCROW) -1;
+ }
+ else if ( bReplace )
+ {
+ rCol = 0;
+ rRow = 0;
+ }
+ else
+ {
+ rCol = (SCCOL) -1;
+ rRow = 0;
+ }
+ }
+ else
+ {
+ if ( rSearchItem.GetPattern() )
+ {
+ rCol = (SCCOL) -1;
+ rRow = 0;
+ }
+ else if ( bReplace )
+ {
+ rCol = 0;
+ rRow = 0;
+ }
+ else
+ {
+ rCol = 0;
+ rRow = (SCROW) -1;
+ }
+ }
+ }
+}
+
+BOOL ScDocument::SearchAndReplace(const SvxSearchItem& rSearchItem,
+ SCCOL& rCol, SCROW& rRow, SCTAB& rTab,
+ ScMarkData& rMark,
+ String& rUndoStr, ScDocument* pUndoDoc)
+{
+ //! getrennte Markierungen pro Tabelle verwalten !!!!!!!!!!!!!
+
+ rMark.MarkToMulti();
+
+ BOOL bFound = FALSE;
+ if (VALIDTAB(rTab))
+ {
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ USHORT nCommand = rSearchItem.GetCommand();
+ if ( nCommand == SVX_SEARCHCMD_FIND_ALL ||
+ nCommand == SVX_SEARCHCMD_REPLACE_ALL )
+ {
+ for (nTab = 0; nTab <= MAXTAB; nTab++)
+ if (pTab[nTab])
+ {
+ if (rMark.GetTableSelect(nTab))
+ {
+ nCol = 0;
+ nRow = 0;
+ bFound |= pTab[nTab]->SearchAndReplace(
+ rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc );
+ }
+ }
+
+ // Markierung wird innen schon komplett gesetzt
+ }
+ else
+ {
+ nCol = rCol;
+ nRow = rRow;
+ if (rSearchItem.GetBackward())
+ {
+ for (nTab = rTab; ((SCsTAB)nTab >= 0) && !bFound; nTab--)
+ if (pTab[nTab])
+ {
+ if (rMark.GetTableSelect(nTab))
+ {
+ bFound = pTab[nTab]->SearchAndReplace(
+ rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc );
+ if (bFound)
+ {
+ rCol = nCol;
+ rRow = nRow;
+ rTab = nTab;
+ }
+ else
+ ScDocument::GetSearchAndReplaceStart(
+ rSearchItem, nCol, nRow );
+ }
+ }
+ }
+ else
+ {
+ for (nTab = rTab; (nTab <= MAXTAB) && !bFound; nTab++)
+ if (pTab[nTab])
+ {
+ if (rMark.GetTableSelect(nTab))
+ {
+ bFound = pTab[nTab]->SearchAndReplace(
+ rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc );
+ if (bFound)
+ {
+ rCol = nCol;
+ rRow = nRow;
+ rTab = nTab;
+ }
+ else
+ ScDocument::GetSearchAndReplaceStart(
+ rSearchItem, nCol, nRow );
+ }
+ }
+ }
+ }
+ }
+ return bFound;
+}
+
+BOOL ScDocument::IsFiltered( SCROW nRow, SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->IsFiltered( nRow );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+// Outline anpassen
+
+BOOL ScDocument::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, SCTAB nTab, BOOL bShow )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->UpdateOutlineCol( nStartCol, nEndCol, bShow );
+
+ DBG_ERROR("missing tab");
+ return FALSE;
+}
+
+BOOL ScDocument::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, BOOL bShow )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->UpdateOutlineRow( nStartRow, nEndRow, bShow );
+
+ DBG_ERROR("missing tab");
+ return FALSE;
+}
+
+void ScDocument::Sort(SCTAB nTab, const ScSortParam& rSortParam, BOOL bKeepQuery)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ BOOL bOldDisableIdle = IsIdleDisabled();
+ DisableIdle( TRUE );
+ pTab[nTab]->Sort(rSortParam, bKeepQuery);
+ DisableIdle( bOldDisableIdle );
+ }
+}
+
+SCSIZE ScDocument::Query(SCTAB nTab, const ScQueryParam& rQueryParam, BOOL bKeepSub)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->Query((ScQueryParam&)rQueryParam, bKeepSub);
+
+ DBG_ERROR("missing tab");
+ return 0;
+}
+
+
+BOOL ScDocument::ValidQuery( SCROW nRow, SCTAB nTab, const ScQueryParam& rQueryParam, BOOL* pSpecial )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->ValidQuery( nRow, rQueryParam, pSpecial );
+
+ DBG_ERROR("missing tab");
+ return FALSE;
+}
+
+
+void ScDocument::GetUpperCellString(SCCOL nCol, SCROW nRow, SCTAB nTab, String& rStr)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->GetUpperCellString( nCol, nRow, rStr );
+ else
+ rStr.Erase();
+}
+
+BOOL ScDocument::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab, ScQueryParam& rQueryParam)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->CreateQueryParam(nCol1, nRow1, nCol2, nRow2, rQueryParam);
+
+ DBG_ERROR("missing tab");
+ return FALSE;
+}
+
+BOOL ScDocument::HasAutoFilter( SCCOL nCurCol, SCROW nCurRow, SCTAB nCurTab )
+{
+ ScDBData* pDBData = GetDBAtCursor( nCurCol, nCurRow, nCurTab );
+ BOOL bHasAutoFilter = ( pDBData != NULL );
+
+ if ( pDBData )
+ {
+ if ( pDBData->HasHeader() )
+ {
+ SCCOL nCol;
+ SCROW nRow;
+ INT16 nFlag;
+
+ ScQueryParam aParam;
+ pDBData->GetQueryParam( aParam );
+ nRow = aParam.nRow1;
+
+ for ( nCol=aParam.nCol1; nCol<=aParam.nCol2 && bHasAutoFilter; nCol++ )
+ {
+ nFlag = ((ScMergeFlagAttr*)
+ GetAttr( nCol, nRow, nCurTab, ATTR_MERGE_FLAG ))->
+ GetValue();
+
+ if ( (nFlag & SC_MF_AUTO) == 0 )
+ bHasAutoFilter = FALSE;
+ }
+ }
+ else
+ bHasAutoFilter = FALSE;
+ }
+
+ return bHasAutoFilter;
+}
+
+BOOL ScDocument::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ SCTAB nTab )
+{
+ return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->HasColHeader( nStartCol, nStartRow, nEndCol, nEndRow );
+ //if (VALIDTAB(nTab))
+ // if (pTab[nTab])
+ // return pTab[nTab]->HasColHeader( nStartCol, nStartRow, nEndCol, nEndRow );
+
+ //return FALSE;
+}
+
+BOOL ScDocument::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ SCTAB nTab )
+{
+ return VALIDTAB(nTab) && pTab[nTab] && pTab[nTab]->HasRowHeader( nStartCol, nStartRow, nEndCol, nEndRow );
+ //if (VALIDTAB(nTab))
+ // if (pTab[nTab])
+ // return pTab[nTab]->HasRowHeader( nStartCol, nStartRow, nEndCol, nEndRow );
+
+ //return FALSE;
+}
+
+//
+// GetFilterEntries - Eintraege fuer AutoFilter-Listbox
+//
+
+BOOL ScDocument::GetFilterEntries( SCCOL nCol, SCROW nRow, SCTAB nTab, TypedScStrCollection& rStrings, bool bFilter )
+{
+ if ( ValidTab(nTab) && pTab[nTab] && pDBCollection )
+ {
+ ScDBData* pDBData = pDBCollection->GetDBAtCursor(nCol, nRow, nTab, FALSE); //!??
+ if (pDBData)
+ {
+ SCTAB nAreaTab;
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
+ if (pDBData->HasHeader())
+ ++nStartRow;
+
+ ScQueryParam aParam;
+ pDBData->GetQueryParam( aParam );
+ rStrings.SetCaseSensitive( aParam.bCaseSens );
+
+ // return all filter entries, if a filter condition is connected with a boolean OR
+ if ( bFilter )
+ {
+ SCSIZE nEntryCount = aParam.GetEntryCount();
+ for ( SCSIZE i = 0; i < nEntryCount && aParam.GetEntry(i).bDoQuery; ++i )
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if ( rEntry.eConnect != SC_AND )
+ {
+ bFilter = false;
+ break;
+ }
+ }
+ }
+
+ if ( bFilter )
+ {
+ pTab[nTab]->GetFilteredFilterEntries( nCol, nStartRow, nEndRow, aParam, rStrings );
+ }
+ else
+ {
+ pTab[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rStrings );
+ }
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+//
+// GetFilterEntriesArea - Eintraege fuer Filter-Dialog
+//
+
+BOOL ScDocument::GetFilterEntriesArea( SCCOL nCol, SCROW nStartRow, SCROW nEndRow,
+ SCTAB nTab, TypedScStrCollection& rStrings )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ pTab[nTab]->GetFilterEntries( nCol, nStartRow, nEndRow, rStrings );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+//
+// GetDataEntries - Eintraege fuer Auswahlliste-Listbox (keine Zahlen / Formeln)
+//
+
+BOOL ScDocument::GetDataEntries( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ TypedScStrCollection& rStrings, BOOL bLimit )
+{
+ if( !bLimit )
+ {
+ /* Try to generate the list from list validation. This part is skipped,
+ if bLimit==TRUE, because in that case this function is called to get
+ cell values for auto completion on input. */
+ sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
+ if( nValidation )
+ {
+ const ScValidationData* pData = GetValidationEntry( nValidation );
+ if( pData && pData->FillSelectionList( rStrings, ScAddress( nCol, nRow, nTab ) ) )
+ return TRUE;
+ }
+ }
+
+ return ValidTab(nTab) && pTab[nTab] && pTab[nTab]->GetDataEntries( nCol, nRow, rStrings, bLimit );
+ //if (ValidTab(nTab) && pTab[nTab])
+ // return pTab[nTab]->GetDataEntries( nCol, nRow, rStrings, bLimit );
+
+ //return FALSE;
+}
+
+//
+// GetFormulaEntries - Eintraege fuer Formel-AutoEingabe
+//
+
+// Funktionen werden als 1 schon vom InputHandler eingefuegt
+#define SC_STRTYPE_NAMES 2
+#define SC_STRTYPE_DBNAMES 3
+#define SC_STRTYPE_HEADERS 4
+
+BOOL ScDocument::GetFormulaEntries( TypedScStrCollection& rStrings )
+{
+ USHORT i;
+
+ //
+ // Bereichsnamen
+ //
+
+ if ( pRangeName )
+ {
+ USHORT nRangeCount = pRangeName->GetCount();
+ for ( i=0; i<nRangeCount; i++ )
+ {
+ ScRangeData* pData = (*pRangeName)[i];
+ if (pData)
+ {
+ TypedStrData* pNew = new TypedStrData( pData->GetName(), 0.0, SC_STRTYPE_NAMES );
+ if ( !rStrings.Insert(pNew) )
+ delete pNew;
+ }
+ }
+ }
+
+ //
+ // Datenbank-Bereiche
+ //
+
+ if ( pDBCollection )
+ {
+ USHORT nDBCount = pDBCollection->GetCount();
+ for ( i=0; i<nDBCount; i++ )
+ {
+ ScDBData* pData = (*pDBCollection)[i];
+ if (pData)
+ {
+ TypedStrData* pNew = new TypedStrData( pData->GetName(), 0.0, SC_STRTYPE_DBNAMES );
+ if ( !rStrings.Insert(pNew) )
+ delete pNew;
+ }
+ }
+ }
+
+ //
+ // Inhalte von Beschriftungsbereichen
+ //
+
+ ScRangePairList* pLists[2];
+ pLists[0] = GetColNameRanges();
+ pLists[1] = GetRowNameRanges();
+ for (USHORT nListNo=0; nListNo<2; nListNo++)
+ {
+ ScRangePairList* pList = pLists[nListNo];
+ if (pList)
+ for ( ScRangePair* pPair = pList->First(); pPair; pPair = pList->Next() )
+ {
+ ScRange aRange = pPair->GetRange(0);
+ ScCellIterator aIter( this, aRange );
+ for ( ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext() )
+ if ( pCell->HasStringData() )
+ {
+ String aStr = pCell->GetStringData();
+ TypedStrData* pNew = new TypedStrData( aStr, 0.0, SC_STRTYPE_HEADERS );
+ if ( !rStrings.Insert(pNew) )
+ delete pNew;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOL ScDocument::IsEmbedded() const
+{
+ return bIsEmbedded;
+}
+
+void ScDocument::GetEmbedded( ScRange& rRange ) const
+{
+ rRange = aEmbedRange;
+}
+
+Rectangle ScDocument::GetEmbeddedRect() const // 1/100 mm
+{
+ Rectangle aRect;
+ ScTable* pTable = pTab[aEmbedRange.aStart.Tab()];
+ if (!pTable)
+ {
+ DBG_ERROR("GetEmbeddedRect ohne Tabelle");
+ }
+ else
+ {
+ SCCOL i;
+
+ for (i=0; i<aEmbedRange.aStart.Col(); i++)
+ aRect.Left() += pTable->GetColWidth(i);
+ aRect.Top() += pTable->GetRowHeight( 0, aEmbedRange.aStart.Row() - 1);
+ aRect.Right() = aRect.Left();
+ for (i=aEmbedRange.aStart.Col(); i<=aEmbedRange.aEnd.Col(); i++)
+ aRect.Right() += pTable->GetColWidth(i);
+ aRect.Bottom() = aRect.Top();
+ aRect.Bottom() += pTable->GetRowHeight( aEmbedRange.aStart.Row(), aEmbedRange.aEnd.Row());
+
+ aRect.Left() = (long) ( aRect.Left() * HMM_PER_TWIPS );
+ aRect.Right() = (long) ( aRect.Right() * HMM_PER_TWIPS );
+ aRect.Top() = (long) ( aRect.Top() * HMM_PER_TWIPS );
+ aRect.Bottom() = (long) ( aRect.Bottom() * HMM_PER_TWIPS );
+ }
+ return aRect;
+}
+
+void ScDocument::SetEmbedded( const ScRange& rRange )
+{
+ bIsEmbedded = TRUE;
+ aEmbedRange = rRange;
+}
+
+void ScDocument::ResetEmbedded()
+{
+ bIsEmbedded = FALSE;
+ aEmbedRange = ScRange();
+}
+
+ScRange ScDocument::GetRange( SCTAB nTab, const Rectangle& rMMRect )
+{
+ ScTable* pTable = pTab[nTab];
+ if (!pTable)
+ {
+ DBG_ERROR("GetRange ohne Tabelle");
+ return ScRange();
+ }
+
+ Rectangle aPosRect = rMMRect;
+ if ( IsNegativePage( nTab ) )
+ ScDrawLayer::MirrorRectRTL( aPosRect ); // always with positive (LTR) values
+
+ long nSize;
+ long nTwips;
+ long nAdd;
+ BOOL bEnd;
+
+ nSize = 0;
+ nTwips = (long) (aPosRect.Left() / HMM_PER_TWIPS);
+
+ SCCOL nX1 = 0;
+ bEnd = FALSE;
+ while (!bEnd)
+ {
+ nAdd = (long) pTable->GetColWidth(nX1);
+ if (nSize+nAdd <= nTwips+1 && nX1<MAXCOL)
+ {
+ nSize += nAdd;
+ ++nX1;
+ }
+ else
+ bEnd = TRUE;
+ }
+
+ nTwips = (long) (aPosRect.Right() / HMM_PER_TWIPS);
+
+ SCCOL nX2 = nX1;
+ bEnd = FALSE;
+ while (!bEnd)
+ {
+ nAdd = (long) pTable->GetColWidth(nX2);
+ if (nSize+nAdd < nTwips && nX2<MAXCOL)
+ {
+ nSize += nAdd;
+ ++nX2;
+ }
+ else
+ bEnd = TRUE;
+ }
+
+
+ nSize = 0;
+ nTwips = (long) (aPosRect.Top() / HMM_PER_TWIPS);
+
+ SCROW nY1 = 0;
+ ScCoupledCompressedArrayIterator< SCROW, BYTE, USHORT> aIter(
+ *(pTable->GetRowFlagsArray()), nY1, MAXROW, CR_HIDDEN, 0,
+ *(pTable->GetRowHeightArray()));
+ bEnd = FALSE;
+ while (!bEnd && aIter)
+ {
+ nY1 = aIter.GetPos();
+ nAdd = (long) *aIter;
+ if (nSize+nAdd <= nTwips+1 && nY1<MAXROW)
+ {
+ nSize += nAdd;
+ ++nY1;
+ ++aIter;
+ }
+ else
+ bEnd = TRUE;
+ }
+ if (!aIter)
+ nY1 = aIter.GetIterEnd(); // all hidden down to the bottom
+
+ nTwips = (long) (aPosRect.Bottom() / HMM_PER_TWIPS);
+
+ SCROW nY2 = nY1;
+ aIter.NewLimits( nY2, MAXROW);
+ bEnd = FALSE;
+ while (!bEnd && aIter)
+ {
+ nY2 = aIter.GetPos();
+ nAdd = (long) *aIter;
+ if (nSize+nAdd < nTwips && nY2<MAXROW)
+ {
+ nSize += nAdd;
+ ++nY2;
+ ++aIter;
+ }
+ else
+ bEnd = TRUE;
+ }
+ if (!aIter)
+ nY2 = aIter.GetIterEnd(); // all hidden down to the bottom
+
+ return ScRange( nX1,nY1,nTab, nX2,nY2,nTab );
+}
+
+void ScDocument::SetEmbedded( const Rectangle& rRect ) // aus VisArea (1/100 mm)
+{
+ bIsEmbedded = TRUE;
+ aEmbedRange = GetRange( nVisibleTab, rRect );
+}
+
+// VisArea auf Zellgrenzen anpassen
+
+void lcl_SnapHor( ScTable* pTable, long& rVal, SCCOL& rStartCol )
+{
+ SCCOL nCol = 0;
+ long nTwips = (long) (rVal / HMM_PER_TWIPS);
+ long nSnap = 0;
+ while ( nCol<MAXCOL )
+ {
+ long nAdd = pTable->GetColWidth(nCol);
+ if ( nSnap + nAdd/2 < nTwips || nCol < rStartCol )
+ {
+ nSnap += nAdd;
+ ++nCol;
+ }
+ else
+ break;
+ }
+ rVal = (long) ( nSnap * HMM_PER_TWIPS );
+ rStartCol = nCol;
+}
+
+void lcl_SnapVer( ScTable* pTable, long& rVal, SCROW& rStartRow )
+{
+ SCROW nRow = 0;
+ long nTwips = (long) (rVal / HMM_PER_TWIPS);
+ long nSnap = 0;
+ ScCoupledCompressedArrayIterator< SCROW, BYTE, USHORT> aIter(
+ *(pTable->GetRowFlagsArray()), nRow, MAXROW, CR_HIDDEN, 0,
+ *(pTable->GetRowHeightArray()));
+ while ( aIter )
+ {
+ nRow = aIter.GetPos();
+ long nAdd = *aIter;
+ if ( nSnap + nAdd/2 < nTwips || nRow < rStartRow )
+ {
+ nSnap += nAdd;
+ ++nRow;
+ ++aIter;
+ }
+ else
+ break;
+ }
+ if (!aIter)
+ nRow = MAXROW; // all hidden down to the bottom
+ rVal = (long) ( nSnap * HMM_PER_TWIPS );
+ rStartRow = nRow;
+}
+
+void ScDocument::SnapVisArea( Rectangle& rRect ) const
+{
+ ScTable* pTable = pTab[nVisibleTab];
+ if (!pTable)
+ {
+ DBG_ERROR("SetEmbedded ohne Tabelle");
+ return;
+ }
+
+ BOOL bNegativePage = IsNegativePage( nVisibleTab );
+ if ( bNegativePage )
+ ScDrawLayer::MirrorRectRTL( rRect ); // calculate with positive (LTR) values
+
+ SCCOL nCol = 0;
+ lcl_SnapHor( pTable, rRect.Left(), nCol );
+ ++nCol; // mindestens eine Spalte
+ lcl_SnapHor( pTable, rRect.Right(), nCol );
+
+ SCROW nRow = 0;
+ lcl_SnapVer( pTable, rRect.Top(), nRow );
+ ++nRow; // mindestens eine Zeile
+ lcl_SnapVer( pTable, rRect.Bottom(), nRow );
+
+ if ( bNegativePage )
+ ScDrawLayer::MirrorRectRTL( rRect ); // back to real rectangle
+}
+
+void ScDocument::SetDocProtection( BOOL bProtect, const uno::Sequence<sal_Int8>& rPasswd )
+{
+ bProtected = bProtect;
+ aProtectPass = rPasswd;
+}
+
+void ScDocument::SetTabProtection( SCTAB nTab, BOOL bProtect, const uno::Sequence<sal_Int8>& rPasswd )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetProtection( bProtect, rPasswd );
+}
+
+BOOL ScDocument::IsDocProtected() const
+{
+ return bProtected;
+}
+
+BOOL ScDocument::IsDocEditable() const
+{
+ // import into read-only document is possible
+ return !bProtected && ( bImportingXML || mbChangeReadOnlyEnabled || !pShell || !pShell->IsReadOnly() );
+}
+
+BOOL ScDocument::IsTabProtected( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab) && pTab[nTab])
+ return pTab[nTab]->IsProtected();
+
+ DBG_ERROR("Falsche Tabellennummer");
+ return FALSE;
+}
+
+const uno::Sequence<sal_Int8>& ScDocument::GetDocPassword() const
+{
+ return aProtectPass;
+}
+
+const uno::Sequence<sal_Int8>& ScDocument::GetTabPassword( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab) && pTab[nTab])
+ return pTab[nTab]->GetPassword();
+
+ DBG_ERROR("Falsche Tabellennummer");
+ return aProtectPass;
+}
+
+const ScDocOptions& ScDocument::GetDocOptions() const
+{
+ DBG_ASSERT( pDocOptions, "No DocOptions! :-(" );
+ return *pDocOptions;
+}
+
+void ScDocument::SetDocOptions( const ScDocOptions& rOpt )
+{
+ USHORT d,m,y;
+
+ DBG_ASSERT( pDocOptions, "No DocOptions! :-(" );
+ *pDocOptions = rOpt;
+ rOpt.GetDate( d,m,y );
+
+ SvNumberFormatter* pFormatter = xPoolHelper->GetFormTable();
+ pFormatter->ChangeNullDate( d,m,y );
+ pFormatter->ChangeStandardPrec( (USHORT)rOpt.GetStdPrecision() );
+ pFormatter->SetYear2000( rOpt.GetYear2000() );
+}
+
+const ScViewOptions& ScDocument::GetViewOptions() const
+{
+ DBG_ASSERT( pViewOptions, "No ViewOptions! :-(" );
+ return *pViewOptions;
+}
+
+void ScDocument::SetViewOptions( const ScViewOptions& rOpt )
+{
+ DBG_ASSERT( pViewOptions, "No ViewOptions! :-(" );
+ *pViewOptions = rOpt;
+}
+
+void ScDocument::GetLanguage( LanguageType& rLatin, LanguageType& rCjk, LanguageType& rCtl ) const
+{
+ rLatin = eLanguage;
+ rCjk = eCjkLanguage;
+ rCtl = eCtlLanguage;
+}
+
+void ScDocument::SetLanguage( LanguageType eLatin, LanguageType eCjk, LanguageType eCtl )
+{
+ eLanguage = eLatin;
+ eCjkLanguage = eCjk;
+ eCtlLanguage = eCtl;
+ if ( xPoolHelper.isValid() )
+ {
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+ pPool->SetPoolDefaultItem( SvxLanguageItem( eLanguage, ATTR_FONT_LANGUAGE ) );
+ pPool->SetPoolDefaultItem( SvxLanguageItem( eCjkLanguage, ATTR_CJK_FONT_LANGUAGE ) );
+ pPool->SetPoolDefaultItem( SvxLanguageItem( eCtlLanguage, ATTR_CTL_FONT_LANGUAGE ) );
+ }
+
+ UpdateDrawLanguages(); // set edit engine defaults in drawing layer pool
+}
+
+void ScDocument::SetDrawDefaults()
+{
+ bSetDrawDefaults = TRUE;
+ UpdateDrawDefaults();
+}
+
+Rectangle ScDocument::GetMMRect( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
+{
+ if (!ValidTab(nTab) || !pTab[nTab])
+ {
+ DBG_ERROR("GetMMRect: falsche Tabelle");
+ return Rectangle(0,0,0,0);
+ }
+
+ SCCOL i;
+ Rectangle aRect;
+
+ for (i=0; i<nStartCol; i++)
+ aRect.Left() += GetColWidth(i,nTab);
+ aRect.Top() += FastGetRowHeight( 0, nStartRow-1, nTab);
+
+ aRect.Right() = aRect.Left();
+ aRect.Bottom() = aRect.Top();
+
+ for (i=nStartCol; i<=nEndCol; i++)
+ aRect.Right() += GetColWidth(i,nTab);
+ aRect.Bottom() += FastGetRowHeight( nStartRow, nEndRow, nTab);
+
+ aRect.Left() = (long)(aRect.Left() * HMM_PER_TWIPS);
+ aRect.Right() = (long)(aRect.Right() * HMM_PER_TWIPS);
+ aRect.Top() = (long)(aRect.Top() * HMM_PER_TWIPS);
+ aRect.Bottom() = (long)(aRect.Bottom() * HMM_PER_TWIPS);
+
+ if ( IsNegativePage( nTab ) )
+ ScDrawLayer::MirrorRectRTL( aRect );
+
+ return aRect;
+}
+
+void ScDocument::SetExtDocOptions( ScExtDocOptions* pNewOptions )
+{
+ delete pExtDocOptions;
+ pExtDocOptions = pNewOptions;
+}
+
+void ScDocument::DoMergeContents( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow )
+{
+ String aEmpty;
+ String aTotal;
+ String aCellStr;
+ SCCOL nCol;
+ SCROW nRow;
+ for (nRow=nStartRow; nRow<=nEndRow; nRow++)
+ for (nCol=nStartCol; nCol<=nEndCol; nCol++)
+ {
+ GetString(nCol,nRow,nTab,aCellStr);
+ if (aCellStr.Len())
+ {
+ if (aTotal.Len())
+ aTotal += ' ';
+ aTotal += aCellStr;
+ }
+ if (nCol != nStartCol || nRow != nStartRow)
+ SetString(nCol,nRow,nTab,aEmpty);
+ }
+
+ SetString(nStartCol,nStartRow,nTab,aTotal);
+}
+
+void ScDocument::DoMerge( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, bool bDeleteCaptions )
+{
+ ScMergeAttr aAttr( nEndCol-nStartCol+1, nEndRow-nStartRow+1 );
+ ApplyAttr( nStartCol, nStartRow, nTab, aAttr );
+
+ if ( nEndCol > nStartCol )
+ ApplyFlagsTab( nStartCol+1, nStartRow, nEndCol, nStartRow, nTab, SC_MF_HOR );
+ if ( nEndRow > nStartRow )
+ ApplyFlagsTab( nStartCol, nStartRow+1, nStartCol, nEndRow, nTab, SC_MF_VER );
+ if ( nEndCol > nStartCol && nEndRow > nStartRow )
+ ApplyFlagsTab( nStartCol+1, nStartRow+1, nEndCol, nEndRow, nTab, SC_MF_HOR | SC_MF_VER );
+
+ // remove all covered notes (removed captions are collected by drawing undo if active)
+ USHORT nDelFlag = IDF_NOTE | (bDeleteCaptions ? 0 : IDF_NOCAPTIONS);
+ if( nStartCol < nEndCol )
+ DeleteAreaTab( nStartCol + 1, nStartRow, nEndCol, nStartRow, nTab, nDelFlag );
+ if( nStartRow < nEndRow )
+ DeleteAreaTab( nStartCol, nStartRow + 1, nEndCol, nEndRow, nTab, nDelFlag );
+}
+
+void ScDocument::RemoveMerge( SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ const ScMergeAttr* pAttr = (const ScMergeAttr*)
+ GetAttr( nCol, nRow, nTab, ATTR_MERGE );
+
+ if ( pAttr->GetColMerge() <= 1 && pAttr->GetRowMerge() <= 1 )
+ return;
+
+ SCCOL nEndCol = nCol + pAttr->GetColMerge() - 1;
+ SCROW nEndRow = nRow + pAttr->GetRowMerge() - 1;
+
+ RemoveFlagsTab( nCol, nRow, nEndCol, nEndRow, nTab, SC_MF_HOR | SC_MF_VER );
+
+ const ScMergeAttr* pDefAttr = (const ScMergeAttr*)
+ &xPoolHelper->GetDocPool()->GetDefaultItem( ATTR_MERGE );
+ ApplyAttr( nCol, nRow, nTab, *pDefAttr );
+}
+
+void ScDocument::ExtendPrintArea( OutputDevice* pDev, SCTAB nTab,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ExtendPrintArea( pDev, nStartCol, nStartRow, rEndCol, nEndRow );
+}
+
+void ScDocument::IncSizeRecalcLevel( SCTAB nTab )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->IncRecalcLevel();
+}
+
+void ScDocument::DecSizeRecalcLevel( SCTAB nTab )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->DecRecalcLevel();
+}
+
+
+
+
diff --git a/sc/source/core/data/documen4.cxx b/sc/source/core/data/documen4.cxx
new file mode 100644
index 000000000000..3c72baff5ba4
--- /dev/null
+++ b/sc/source/core/data/documen4.cxx
@@ -0,0 +1,1190 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: documen4.cxx,v $
+ * $Revision: 1.23.102.2 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <svtools/intitem.hxx>
+#include <svtools/zforlist.hxx>
+#include <vcl/sound.hxx>
+#include <formula/token.hxx>
+
+#include "document.hxx"
+#include "table.hxx"
+#include "globstr.hrc"
+#include "subtotal.hxx"
+#include "docoptio.hxx"
+#include "interpre.hxx"
+#include "markdata.hxx"
+#include "validat.hxx"
+#include "scitems.hxx"
+#include "stlpool.hxx"
+#include "poolhelp.hxx"
+#include "detdata.hxx"
+#include "patattr.hxx"
+#include "chgtrack.hxx"
+#include "progress.hxx"
+#include "paramisc.hxx"
+#include "compiler.hxx"
+#include "externalrefmgr.hxx"
+
+using namespace formula;
+
+// -----------------------------------------------------------------------
+
+// Nach der Regula Falsi Methode
+BOOL ScDocument::Solver(SCCOL nFCol, SCROW nFRow, SCTAB nFTab,
+ SCCOL nVCol, SCROW nVRow, SCTAB nVTab,
+ const String& sValStr, double& nX)
+{
+ BOOL bRet = FALSE;
+ nX = 0.0;
+ if (ValidColRow(nFCol, nFRow) && ValidColRow(nVCol, nVRow) &&
+ VALIDTAB(nFTab) && VALIDTAB(nVTab) && pTab[nFTab] && pTab[nVTab])
+ {
+ CellType eFType, eVType;
+ GetCellType(nFCol, nFRow, nFTab, eFType);
+ GetCellType(nVCol, nVRow, nVTab, eVType);
+ // CELLTYPE_NOTE: kein Value aber von Formel referiert
+ if (eFType == CELLTYPE_FORMULA && (eVType == CELLTYPE_VALUE
+ || eVType == CELLTYPE_NOTE) )
+ {
+ ScSingleRefData aRefData;
+ aRefData.InitFlags();
+ aRefData.nCol = nVCol;
+ aRefData.nRow = nVRow;
+ aRefData.nTab = nVTab;
+
+ ScTokenArray aArr;
+ aArr.AddOpCode( ocBackSolver );
+ aArr.AddOpCode( ocOpen );
+ aArr.AddSingleReference( aRefData );
+ aArr.AddOpCode( ocSep );
+
+ aRefData.nCol = nFCol;
+ aRefData.nRow = nFRow;
+ aRefData.nTab = nFTab;
+
+ aArr.AddSingleReference( aRefData );
+ aArr.AddOpCode( ocSep );
+ aArr.AddString( sValStr.GetBuffer() );
+ aArr.AddOpCode( ocClose );
+ aArr.AddOpCode( ocStop );
+
+ ScFormulaCell* pCell = new ScFormulaCell( this, ScAddress(), &aArr );
+
+ if (pCell)
+ {
+ // FIXME FIXME FIXME this might need to be reworked now that we have formula::FormulaErrorToken and ScFormulaResult, double check !!!
+ DBG_ERRORFILE("ScDocument::Solver: -> ScFormulaCell::GetValueAlways might need reimplementation");
+ pCell->Interpret();
+ USHORT nErrCode = pCell->GetErrCode();
+ nX = pCell->GetValueAlways();
+ if (nErrCode == 0) // kein fehler beim Rechnen
+ bRet = TRUE;
+ delete pCell;
+ }
+ }
+ }
+ return bRet;
+}
+
+void ScDocument::InsertMatrixFormula(SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark,
+ const String& rFormula,
+ const ScTokenArray* pArr,
+ const formula::FormulaGrammar::Grammar eGram )
+{
+ PutInOrder(nCol1, nCol2);
+ PutInOrder(nRow1, nRow2);
+ SCTAB i, nTab1;
+ SCCOL j;
+ SCROW k;
+ i = 0;
+ BOOL bStop = FALSE;
+ while (i <= MAXTAB && !bStop) // erste markierte Tabelle finden
+ {
+ if (pTab[i] && rMark.GetTableSelect(i))
+ bStop = TRUE;
+ else
+ i++;
+ }
+ nTab1 = i;
+ if (i == MAXTAB + 1)
+ {
+ Sound::Beep();
+ DBG_ERROR("ScDocument::InsertMatrixFormula Keine Tabelle markiert");
+ return;
+ }
+
+ ScFormulaCell* pCell;
+ ScAddress aPos( nCol1, nRow1, nTab1 );
+ if (pArr)
+ pCell = new ScFormulaCell( this, aPos, pArr, eGram, MM_FORMULA );
+ else
+ pCell = new ScFormulaCell( this, aPos, rFormula, eGram, MM_FORMULA );
+ pCell->SetMatColsRows( nCol2 - nCol1 + 1, nRow2 - nRow1 + 1 );
+ for (i = 0; i <= MAXTAB; i++)
+ {
+ if (pTab[i] && rMark.GetTableSelect(i))
+ {
+ if (i == nTab1)
+ pTab[i]->PutCell(nCol1, nRow1, pCell);
+ else
+ pTab[i]->PutCell(nCol1, nRow1, pCell->CloneWithoutNote(*this, ScAddress( nCol1, nRow1, i), SC_CLONECELL_STARTLISTENING));
+ }
+ }
+
+ ScSingleRefData aRefData;
+ aRefData.InitFlags();
+ aRefData.nCol = nCol1;
+ aRefData.nRow = nRow1;
+ aRefData.nTab = nTab1;
+ aRefData.SetColRel( TRUE );
+ aRefData.SetRowRel( TRUE );
+ aRefData.SetTabRel( TRUE );
+ aRefData.CalcRelFromAbs( ScAddress( nCol1, nRow1, nTab1 ) );
+
+ ScTokenArray aArr;
+ ScToken* t = static_cast<ScToken*>(aArr.AddMatrixSingleReference( aRefData));
+
+ for (i = 0; i <= MAXTAB; i++)
+ {
+ if (pTab[i] && rMark.GetTableSelect(i))
+ {
+ pTab[i]->DoColResize( nCol1, nCol2, static_cast<SCSIZE>(nRow2 - nRow1 + 1) );
+ if (i != nTab1)
+ {
+ aRefData.nTab = i;
+ aRefData.nRelTab = i - nTab1;
+ t->GetSingleRef() = aRefData;
+ }
+ for (j = nCol1; j <= nCol2; j++)
+ {
+ for (k = nRow1; k <= nRow2; k++)
+ {
+ if (j != nCol1 || k != nRow1) // nicht in der ersten Zelle
+ {
+ // Array muss geklont werden, damit jede
+ // Zelle ein eigenes Array erhaelt!
+ aPos = ScAddress( j, k, i );
+ t->CalcRelFromAbs( aPos );
+ pCell = new ScFormulaCell( this, aPos, aArr.Clone(), eGram, MM_REFERENCE );
+ pTab[i]->PutCell(j, k, (ScBaseCell*) pCell);
+ }
+ }
+ }
+ }
+ }
+}
+
+void ScDocument::InsertTableOp(const ScTabOpParam& rParam, // Mehrfachoperation
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark)
+{
+ PutInOrder(nCol1, nCol2);
+ PutInOrder(nRow1, nRow2);
+ SCTAB i, nTab1;
+ SCCOL j;
+ SCROW k;
+ i = 0;
+ BOOL bStop = FALSE;
+ while (i <= MAXTAB && !bStop) // erste markierte Tabelle finden
+ {
+ if (pTab[i] && rMark.GetTableSelect(i))
+ bStop = TRUE;
+ else
+ i++;
+ }
+ nTab1 = i;
+ if (i == MAXTAB + 1)
+ {
+ Sound::Beep();
+ DBG_ERROR("ScDocument::InsertTableOp: Keine Tabelle markiert");
+ return;
+ }
+
+ ScRefAddress aRef;
+ String aForString = '=';
+ aForString += ScCompiler::GetNativeSymbol(ocTableOp);
+ aForString += ScCompiler::GetNativeSymbol( ocOpen);
+
+ const String& sSep = ScCompiler::GetNativeSymbol( ocSep);
+ if (rParam.nMode == 0) // nur Spalte
+ {
+ aRef.Set( rParam.aRefFormulaCell.GetAddress(), TRUE, FALSE, FALSE );
+ aForString += aRef.GetRefString(this, nTab1);
+ aForString += sSep;
+ aForString += rParam.aRefColCell.GetRefString(this, nTab1);
+ aForString += sSep;
+ aRef.Set( nCol1, nRow1, nTab1, FALSE, TRUE, TRUE );
+ aForString += aRef.GetRefString(this, nTab1);
+ nCol1++;
+ nCol2 = Min( nCol2, (SCCOL)(rParam.aRefFormulaEnd.Col() -
+ rParam.aRefFormulaCell.Col() + nCol1 + 1));
+ }
+ else if (rParam.nMode == 1) // nur zeilenweise
+ {
+ aRef.Set( rParam.aRefFormulaCell.GetAddress(), FALSE, TRUE, FALSE );
+ aForString += aRef.GetRefString(this, nTab1);
+ aForString += sSep;
+ aForString += rParam.aRefRowCell.GetRefString(this, nTab1);
+ aForString += sSep;
+ aRef.Set( nCol1, nRow1, nTab1, TRUE, FALSE, TRUE );
+ aForString += aRef.GetRefString(this, nTab1);
+ nRow1++;
+ nRow2 = Min( nRow2, (SCROW)(rParam.aRefFormulaEnd.Row() -
+ rParam.aRefFormulaCell.Row() + nRow1 + 1));
+ }
+ else // beides
+ {
+ aForString += rParam.aRefFormulaCell.GetRefString(this, nTab1);
+ aForString += sSep;
+ aForString += rParam.aRefColCell.GetRefString(this, nTab1);
+ aForString += sSep;
+ aRef.Set( nCol1, nRow1 + 1, nTab1, FALSE, TRUE, TRUE );
+ aForString += aRef.GetRefString(this, nTab1);
+ aForString += sSep;
+ aForString += rParam.aRefRowCell.GetRefString(this, nTab1);
+ aForString += sSep;
+ aRef.Set( nCol1 + 1, nRow1, nTab1, TRUE, FALSE, TRUE );
+ aForString += aRef.GetRefString(this, nTab1);
+ nCol1++; nRow1++;
+ }
+ aForString += ScCompiler::GetNativeSymbol( ocClose);
+
+ ScFormulaCell aRefCell( this, ScAddress( nCol1, nRow1, nTab1 ), aForString,
+ formula::FormulaGrammar::GRAM_NATIVE, MM_NONE );
+ for( j = nCol1; j <= nCol2; j++ )
+ for( k = nRow1; k <= nRow2; k++ )
+ for (i = 0; i <= MAXTAB; i++)
+ if( pTab[i] && rMark.GetTableSelect(i) )
+ pTab[i]->PutCell( j, k, aRefCell.CloneWithoutNote( *this, ScAddress( j, k, i ), SC_CLONECELL_STARTLISTENING ) );
+}
+
+bool ScDocument::MarkUsedExternalReferences( ScTokenArray & rArr )
+{
+ bool bAllMarked = false;
+ if (rArr.GetLen())
+ {
+ ScExternalRefManager* pRefMgr = NULL;
+ rArr.Reset();
+ ScToken* t;
+ while (!bAllMarked && (t = static_cast<ScToken*>(rArr.GetNextReferenceOrName())) != NULL)
+ {
+ if (t->GetOpCode() == ocExternalRef)
+ {
+ if (!pRefMgr)
+ pRefMgr = GetExternalRefManager();
+ switch (t->GetType())
+ {
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ bAllMarked = pRefMgr->setCacheTableReferenced(
+ t->GetIndex(), t->GetString());
+ break;
+ case svExternalName:
+ /* TODO: external names aren't supported yet, but would
+ * have to be marked as well, if so. Mechanism would be
+ * different. */
+ DBG_ERRORFILE("ScDocument::MarkUsedExternalReferences: implement the svExternalName case!");
+ break;
+ default: break;
+ }
+ }
+ }
+ }
+ return bAllMarked;
+}
+
+BOOL ScDocument::GetNextSpellingCell(SCCOL& nCol, SCROW& nRow, SCTAB nTab,
+ BOOL bInSel, const ScMarkData& rMark) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetNextSpellingCell( nCol, nRow, bInSel, rMark );
+ else
+ return FALSE;
+}
+
+BOOL ScDocument::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, SCTAB nTab,
+ const ScMarkData& rMark )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetNextMarkedCell( rCol, rRow, rMark );
+ else
+ return FALSE;
+}
+
+BOOL ScDocument::ReplaceStyle(const SvxSearchItem& rSearchItem,
+ SCCOL nCol, SCROW nRow, SCTAB nTab,
+ ScMarkData& rMark,
+ BOOL bIsUndoP)
+{
+ if (pTab[nTab])
+ return pTab[nTab]->ReplaceStyle(rSearchItem, nCol, nRow, rMark, bIsUndoP);
+ else
+ return FALSE;
+}
+
+void ScDocument::CompileDBFormula()
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ {
+ if (pTab[i]) pTab[i]->CompileDBFormula();
+ }
+}
+
+void ScDocument::CompileDBFormula( BOOL bCreateFormulaString )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ {
+ if (pTab[i]) pTab[i]->CompileDBFormula( bCreateFormulaString );
+ }
+}
+
+void ScDocument::CompileNameFormula( BOOL bCreateFormulaString )
+{
+ if ( pCondFormList )
+ pCondFormList->CompileAll(); // nach ScNameDlg noetig
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ {
+ if (pTab[i]) pTab[i]->CompileNameFormula( bCreateFormulaString );
+ }
+}
+
+void ScDocument::CompileColRowNameFormula()
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ {
+ if (pTab[i]) pTab[i]->CompileColRowNameFormula();
+ }
+}
+
+void ScDocument::DoColResize( SCTAB nTab, SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->DoColResize( nCol1, nCol2, nAdd );
+ else
+ {
+ DBG_ERROR("DoColResize: falsche Tabelle");
+ }
+}
+
+void ScDocument::InvalidateTableArea()
+{
+ for (SCTAB nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++)
+ {
+ pTab[nTab]->InvalidateTableArea();
+ if ( pTab[nTab]->IsScenario() )
+ pTab[nTab]->InvalidateScenarioRanges();
+ }
+}
+
+sal_Int32 ScDocument::GetMaxStringLen( SCTAB nTab, SCCOL nCol,
+ SCROW nRowStart, SCROW nRowEnd, CharSet eCharSet ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetMaxStringLen( nCol, nRowStart, nRowEnd, eCharSet );
+ else
+ return 0;
+}
+
+xub_StrLen ScDocument::GetMaxNumberStringLen( USHORT& nPrecision, SCTAB nTab,
+ SCCOL nCol,
+ SCROW nRowStart, SCROW nRowEnd ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetMaxNumberStringLen( nPrecision, nCol,
+ nRowStart, nRowEnd );
+ else
+ return 0;
+}
+
+BOOL ScDocument::GetSelectionFunction( ScSubTotalFunc eFunc,
+ const ScAddress& rCursor, const ScMarkData& rMark,
+ double& rResult )
+{
+ ScFunctionData aData(eFunc);
+
+ ScRange aSingle( rCursor );
+ if ( rMark.IsMarked() )
+ rMark.GetMarkArea(aSingle);
+
+ SCCOL nStartCol = aSingle.aStart.Col();
+ SCROW nStartRow = aSingle.aStart.Row();
+ SCCOL nEndCol = aSingle.aEnd.Col();
+ SCROW nEndRow = aSingle.aEnd.Row();
+
+ for (SCTAB nTab=0; nTab<=MAXTAB && !aData.bError; nTab++)
+ if (pTab[nTab] && rMark.GetTableSelect(nTab))
+ pTab[nTab]->UpdateSelectionFunction( aData,
+ nStartCol, nStartRow, nEndCol, nEndRow, rMark );
+
+ //! rMark an UpdateSelectionFunction uebergeben !!!!!
+
+ if (!aData.bError)
+ switch (eFunc)
+ {
+ case SUBTOTAL_FUNC_SUM:
+ rResult = aData.nVal;
+ break;
+ case SUBTOTAL_FUNC_CNT:
+ case SUBTOTAL_FUNC_CNT2:
+ rResult = aData.nCount;
+ break;
+ case SUBTOTAL_FUNC_AVE:
+ if (aData.nCount)
+ rResult = aData.nVal / (double) aData.nCount;
+ else
+ aData.bError = TRUE;
+ break;
+ case SUBTOTAL_FUNC_MAX:
+ case SUBTOTAL_FUNC_MIN:
+ if (aData.nCount)
+ rResult = aData.nVal;
+ else
+ aData.bError = TRUE;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (aData.bError)
+ rResult = 0.0;
+
+ return !aData.bError;
+}
+
+double ScDocument::RoundValueAsShown( double fVal, ULONG nFormat )
+{
+ short nType;
+ if ( (nType = GetFormatTable()->GetType( nFormat )) != NUMBERFORMAT_DATE
+ && nType != NUMBERFORMAT_TIME && nType != NUMBERFORMAT_DATETIME )
+ {
+ short nPrecision;
+ if ( nFormat )
+ {
+ nPrecision = (short)GetFormatTable()->GetFormatPrecision( nFormat );
+ switch ( nType )
+ {
+ case NUMBERFORMAT_PERCENT: // 0,41% == 0,0041
+ nPrecision += 2;
+ break;
+ case NUMBERFORMAT_SCIENTIFIC: // 1,23e-3 == 0,00123
+ {
+ if ( fVal > 0.0 )
+ nPrecision = sal::static_int_cast<short>( nPrecision - (short)floor( log10( fVal ) ) );
+ else if ( fVal < 0.0 )
+ nPrecision = sal::static_int_cast<short>( nPrecision - (short)floor( log10( -fVal ) ) );
+ break;
+ }
+ }
+ }
+ else
+ nPrecision = (short)GetDocOptions().GetStdPrecision();
+ double fRound = ::rtl::math::round( fVal, nPrecision );
+ if ( ::rtl::math::approxEqual( fVal, fRound ) )
+ return fVal; // durch Rundung hoechstens Fehler
+ else
+ return fRound;
+ }
+ else
+ return fVal;
+}
+
+//
+// bedingte Formate und Gueltigkeitsbereiche
+//
+
+ULONG ScDocument::AddCondFormat( const ScConditionalFormat& rNew )
+{
+ if (rNew.IsEmpty())
+ return 0; // leer ist immer 0
+
+ if (!pCondFormList)
+ pCondFormList = new ScConditionalFormatList;
+
+ ULONG nMax = 0;
+ USHORT nCount = pCondFormList->Count();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ const ScConditionalFormat* pForm = (*pCondFormList)[i];
+ ULONG nKey = pForm->GetKey();
+ if ( pForm->EqualEntries( rNew ) )
+ return nKey;
+ if ( nKey > nMax )
+ nMax = nKey;
+ }
+
+ // Der Aufruf kann aus ScPatternAttr::PutInPool kommen, darum Clone (echte Kopie)
+
+ ULONG nNewKey = nMax + 1;
+ ScConditionalFormat* pInsert = rNew.Clone(this);
+ pInsert->SetKey( nNewKey );
+ pCondFormList->InsertNew( pInsert );
+ return nNewKey;
+}
+
+ULONG ScDocument::AddValidationEntry( const ScValidationData& rNew )
+{
+ if (rNew.IsEmpty())
+ return 0; // leer ist immer 0
+
+ if (!pValidationList)
+ pValidationList = new ScValidationDataList;
+
+ ULONG nMax = 0;
+ USHORT nCount = pValidationList->Count();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ const ScValidationData* pData = (*pValidationList)[i];
+ ULONG nKey = pData->GetKey();
+ if ( pData->EqualEntries( rNew ) )
+ return nKey;
+ if ( nKey > nMax )
+ nMax = nKey;
+ }
+
+ // Der Aufruf kann aus ScPatternAttr::PutInPool kommen, darum Clone (echte Kopie)
+
+ ULONG nNewKey = nMax + 1;
+ ScValidationData* pInsert = rNew.Clone(this);
+ pInsert->SetKey( nNewKey );
+ pValidationList->InsertNew( pInsert );
+ return nNewKey;
+}
+
+const SfxPoolItem* ScDocument::GetEffItem(
+ SCCOL nCol, SCROW nRow, SCTAB nTab, USHORT nWhich ) const
+{
+ const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
+ if ( pPattern )
+ {
+ const SfxItemSet& rSet = pPattern->GetItemSet();
+ const SfxPoolItem* pItem;
+ if ( rSet.GetItemState( ATTR_CONDITIONAL, TRUE, &pItem ) == SFX_ITEM_SET )
+ {
+ ULONG nIndex = ((const SfxUInt32Item*)pItem)->GetValue();
+ if (nIndex && pCondFormList)
+ {
+ const ScConditionalFormat* pForm = pCondFormList->GetFormat( nIndex );
+ if ( pForm )
+ {
+ ScBaseCell* pCell = ((ScDocument*)this)->GetCell(ScAddress(nCol,nRow,nTab));
+ String aStyle = pForm->GetCellStyle( pCell, ScAddress(nCol, nRow, nTab) );
+ if (aStyle.Len())
+ {
+ SfxStyleSheetBase* pStyleSheet = xPoolHelper->GetStylePool()->Find(
+ aStyle, SFX_STYLE_FAMILY_PARA );
+ if ( pStyleSheet && pStyleSheet->GetItemSet().GetItemState(
+ nWhich, TRUE, &pItem ) == SFX_ITEM_SET )
+ return pItem;
+ }
+ }
+ }
+ }
+ return &rSet.Get( nWhich );
+ }
+ DBG_ERROR("kein Pattern");
+ return NULL;
+}
+
+const SfxItemSet* ScDocument::GetCondResult( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ const ScConditionalFormat* pForm = GetCondFormat( nCol, nRow, nTab );
+ if ( pForm )
+ {
+ ScBaseCell* pCell = ((ScDocument*)this)->GetCell(ScAddress(nCol,nRow,nTab));
+ String aStyle = pForm->GetCellStyle( pCell, ScAddress(nCol, nRow, nTab) );
+ if (aStyle.Len())
+ {
+ SfxStyleSheetBase* pStyleSheet = xPoolHelper->GetStylePool()->Find( aStyle, SFX_STYLE_FAMILY_PARA );
+ if ( pStyleSheet )
+ return &pStyleSheet->GetItemSet();
+ // if style is not there, treat like no condition
+ }
+ }
+ return NULL;
+}
+
+const ScConditionalFormat* ScDocument::GetCondFormat(
+ SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ ULONG nIndex = ((const SfxUInt32Item*)GetAttr(nCol,nRow,nTab,ATTR_CONDITIONAL))->GetValue();
+ if (nIndex)
+ {
+ if (pCondFormList)
+ return pCondFormList->GetFormat( nIndex );
+ else
+ {
+ DBG_ERROR("pCondFormList ist 0");
+ }
+ }
+
+ return NULL;
+}
+
+const ScValidationData* ScDocument::GetValidationEntry( ULONG nIndex ) const
+{
+ if ( pValidationList )
+ return pValidationList->GetData( nIndex );
+ else
+ return NULL;
+}
+
+void ScDocument::FindConditionalFormat( ULONG nKey, ScRangeList& rRanges )
+{
+ for (SCTAB i=0; i<=MAXTAB && pTab[i]; i++)
+ pTab[i]->FindConditionalFormat( nKey, rRanges );
+}
+
+void ScDocument::FindConditionalFormat( ULONG nKey, ScRangeList& rRanges, SCTAB nTab )
+{
+ if(VALIDTAB(nTab) && pTab[nTab])
+ pTab[nTab]->FindConditionalFormat( nKey, rRanges );
+}
+
+void ScDocument::ConditionalChanged( ULONG nKey )
+{
+ if ( nKey && pCondFormList && !bIsClip && !bIsUndo ) // nKey==0 -> noop
+ {
+ ScConditionalFormat* pForm = pCondFormList->GetFormat( nKey );
+ if (pForm)
+ pForm->InvalidateArea();
+ }
+}
+
+void ScDocument::SetCondFormList(ScConditionalFormatList* pNew)
+{
+ if (pCondFormList)
+ {
+ pCondFormList->DeleteAndDestroy( 0, pCondFormList->Count() );
+ delete pCondFormList;
+ }
+
+ pCondFormList = pNew;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScDocument::HasDetectiveOperations() const
+{
+ return pDetOpList && pDetOpList->Count();
+}
+
+void ScDocument::AddDetectiveOperation( const ScDetOpData& rData )
+{
+ if (!pDetOpList)
+ pDetOpList = new ScDetOpList;
+
+ pDetOpList->Append( new ScDetOpData( rData ) );
+}
+
+void ScDocument::ClearDetectiveOperations()
+{
+ delete pDetOpList; // loescht auch die Eintraege
+ pDetOpList = NULL;
+}
+
+void ScDocument::SetDetOpList(ScDetOpList* pNew)
+{
+ delete pDetOpList; // loescht auch die Eintraege
+ pDetOpList = pNew;
+}
+
+//------------------------------------------------------------------------
+//
+// Vergleich von Dokumenten
+//
+//------------------------------------------------------------------------
+
+// Pfriemel-Faktoren
+#define SC_DOCCOMP_MAXDIFF 256
+#define SC_DOCCOMP_MINGOOD 128
+#define SC_DOCCOMP_COLUMNS 10
+#define SC_DOCCOMP_ROWS 100
+
+
+USHORT ScDocument::RowDifferences( SCROW nThisRow, SCTAB nThisTab,
+ ScDocument& rOtherDoc, SCROW nOtherRow, SCTAB nOtherTab,
+ SCCOL nMaxCol, SCCOLROW* pOtherCols )
+{
+ ULONG nDif = 0;
+ ULONG nUsed = 0;
+ for (SCCOL nThisCol=0; nThisCol<=nMaxCol; nThisCol++)
+ {
+ SCCOL nOtherCol;
+ if ( pOtherCols )
+ nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
+ else
+ nOtherCol = nThisCol;
+
+ if (ValidCol(nOtherCol)) // nur Spalten vergleichen, die in beiden Dateien sind
+ {
+ const ScBaseCell* pThisCell = GetCell( ScAddress( nThisCol, nThisRow, nThisTab ) );
+ const ScBaseCell* pOtherCell = rOtherDoc.GetCell( ScAddress( nOtherCol, nOtherRow, nOtherTab ) );
+ if (!ScBaseCell::CellEqual( pThisCell, pOtherCell ))
+ {
+ if ( pThisCell && pOtherCell )
+ nDif += 3;
+ else
+ nDif += 4; // Inhalt <-> leer zaehlt mehr
+ }
+
+ if ( ( pThisCell && pThisCell->GetCellType()!=CELLTYPE_NOTE ) ||
+ ( pOtherCell && pOtherCell->GetCellType()!=CELLTYPE_NOTE ) )
+ ++nUsed;
+ }
+ }
+
+ if (nUsed > 0)
+ return static_cast<USHORT>((nDif*64)/nUsed); // max.256 (SC_DOCCOMP_MAXDIFF)
+
+ DBG_ASSERT(!nDif,"Diff ohne Used");
+ return 0;
+}
+
+USHORT ScDocument::ColDifferences( SCCOL nThisCol, SCTAB nThisTab,
+ ScDocument& rOtherDoc, SCCOL nOtherCol, SCTAB nOtherTab,
+ SCROW nMaxRow, SCCOLROW* pOtherRows )
+{
+ //! optimieren mit Iterator oder so
+
+ ULONG nDif = 0;
+ ULONG nUsed = 0;
+ for (SCROW nThisRow=0; nThisRow<=nMaxRow; nThisRow++)
+ {
+ SCROW nOtherRow;
+ if ( pOtherRows )
+ nOtherRow = pOtherRows[nThisRow];
+ else
+ nOtherRow = nThisRow;
+
+ if (ValidRow(nOtherRow)) // nur Zeilen vergleichen, die in beiden Dateien sind
+ {
+ const ScBaseCell* pThisCell = GetCell( ScAddress( nThisCol, nThisRow, nThisTab ) );
+ const ScBaseCell* pOtherCell = rOtherDoc.GetCell( ScAddress( nOtherCol, nOtherRow, nOtherTab ) );
+ if (!ScBaseCell::CellEqual( pThisCell, pOtherCell ))
+ {
+ if ( pThisCell && pOtherCell )
+ nDif += 3;
+ else
+ nDif += 4; // Inhalt <-> leer zaehlt mehr
+ }
+
+ if ( ( pThisCell && pThisCell->GetCellType()!=CELLTYPE_NOTE ) ||
+ ( pOtherCell && pOtherCell->GetCellType()!=CELLTYPE_NOTE ) )
+ ++nUsed;
+ }
+ }
+
+ if (nUsed > 0)
+ return static_cast<USHORT>((nDif*64)/nUsed); // max.256
+
+ DBG_ASSERT(!nDif,"Diff ohne Used");
+ return 0;
+}
+
+void ScDocument::FindOrder( SCCOLROW* pOtherRows, SCCOLROW nThisEndRow, SCCOLROW nOtherEndRow,
+ BOOL bColumns, ScDocument& rOtherDoc, SCTAB nThisTab, SCTAB nOtherTab,
+ SCCOLROW nEndCol, SCCOLROW* pTranslate, ScProgress* pProgress, ULONG nProAdd )
+{
+ // bColumns=TRUE: Zeilen sind Spalten und umgekehrt
+
+ SCCOLROW nMaxCont; // wieviel weiter
+ SCCOLROW nMinGood; // was ist ein Treffer (incl.)
+ if ( bColumns )
+ {
+ nMaxCont = SC_DOCCOMP_COLUMNS; // 10 Spalten
+ nMinGood = SC_DOCCOMP_MINGOOD;
+ //! Extra Durchgang mit nMinGood = 0 ????
+ }
+ else
+ {
+ nMaxCont = SC_DOCCOMP_ROWS; // 100 Zeilen
+ nMinGood = SC_DOCCOMP_MINGOOD;
+ }
+ BOOL bUseTotal = bColumns && !pTranslate; // nur beim ersten Durchgang
+
+
+ SCCOLROW nOtherRow = 0;
+ USHORT nComp;
+ SCCOLROW nThisRow;
+ BOOL bTotal = FALSE; // ueber verschiedene nThisRow beibehalten
+ SCCOLROW nUnknown = 0;
+ for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
+ {
+ SCCOLROW nTempOther = nOtherRow;
+ BOOL bFound = FALSE;
+ USHORT nBest = SC_DOCCOMP_MAXDIFF;
+ SCCOLROW nMax = Min( nOtherEndRow, static_cast<SCCOLROW>(( nTempOther + nMaxCont + nUnknown )) );
+ for (SCCOLROW i=nTempOther; i<=nMax && nBest>0; i++) // bei 0 abbrechen
+ {
+ if (bColumns)
+ nComp = ColDifferences( static_cast<SCCOL>(nThisRow), nThisTab, rOtherDoc, static_cast<SCCOL>(i), nOtherTab, nEndCol, pTranslate );
+ else
+ nComp = RowDifferences( nThisRow, nThisTab, rOtherDoc, i, nOtherTab, static_cast<SCCOL>(nEndCol), pTranslate );
+ if ( nComp < nBest && ( nComp <= nMinGood || bTotal ) )
+ {
+ nTempOther = i;
+ nBest = nComp;
+ bFound = TRUE;
+ }
+ if ( nComp < SC_DOCCOMP_MAXDIFF || bFound )
+ bTotal = FALSE;
+ else if ( i == nTempOther && bUseTotal )
+ bTotal = TRUE; // nur ganz oben
+ }
+ if ( bFound )
+ {
+ pOtherRows[nThisRow] = nTempOther;
+ nOtherRow = nTempOther + 1;
+ nUnknown = 0;
+ }
+ else
+ {
+ pOtherRows[nThisRow] = SCROW_MAX;
+ ++nUnknown;
+ }
+
+ if (pProgress)
+ pProgress->SetStateOnPercent(nProAdd+static_cast<ULONG>(nThisRow));
+ }
+
+ // Bloecke ohne Uebereinstimmung ausfuellen
+
+ SCROW nFillStart = 0;
+ SCROW nFillPos = 0;
+ BOOL bInFill = FALSE;
+ for (nThisRow = 0; nThisRow <= nThisEndRow+1; nThisRow++)
+ {
+ SCROW nThisOther = ( nThisRow <= nThisEndRow ) ? pOtherRows[nThisRow] : (nOtherEndRow+1);
+ if ( ValidRow(nThisOther) )
+ {
+ if ( bInFill )
+ {
+ if ( nThisOther > nFillStart ) // ist was zu verteilen da?
+ {
+ SCROW nDiff1 = nThisOther - nFillStart;
+ SCROW nDiff2 = nThisRow - nFillPos;
+ SCROW nMinDiff = Min(nDiff1, nDiff2);
+ for (SCROW i=0; i<nMinDiff; i++)
+ pOtherRows[nFillPos+i] = nFillStart+i;
+ }
+
+ bInFill = FALSE;
+ }
+ nFillStart = nThisOther + 1;
+ nFillPos = nThisRow + 1;
+ }
+ else
+ bInFill = TRUE;
+ }
+}
+
+void ScDocument::CompareDocument( ScDocument& rOtherDoc )
+{
+ if (!pChangeTrack)
+ return;
+
+ SCTAB nThisCount = GetTableCount();
+ SCTAB nOtherCount = rOtherDoc.GetTableCount();
+ SCTAB* pOtherTabs = new SCTAB[nThisCount];
+ SCTAB nThisTab;
+
+ // Tabellen mit gleichen Namen vergleichen
+ String aThisName;
+ String aOtherName;
+ for (nThisTab=0; nThisTab<nThisCount; nThisTab++)
+ {
+ SCTAB nOtherTab = SCTAB_MAX;
+ if (!IsScenario(nThisTab)) // Szenarien weglassen
+ {
+ GetName( nThisTab, aThisName );
+ for (SCTAB nTemp=0; nTemp<nOtherCount && nOtherTab>MAXTAB; nTemp++)
+ if (!rOtherDoc.IsScenario(nTemp))
+ {
+ rOtherDoc.GetName( nTemp, aOtherName );
+ if ( aThisName == aOtherName )
+ nOtherTab = nTemp;
+ }
+ }
+ pOtherTabs[nThisTab] = nOtherTab;
+ }
+ // auffuellen, damit einzeln umbenannte Tabellen nicht wegfallen
+ SCTAB nFillStart = 0;
+ SCTAB nFillPos = 0;
+ BOOL bInFill = FALSE;
+ for (nThisTab = 0; nThisTab <= nThisCount; nThisTab++)
+ {
+ SCTAB nThisOther = ( nThisTab < nThisCount ) ? pOtherTabs[nThisTab] : nOtherCount;
+ if ( ValidTab(nThisOther) )
+ {
+ if ( bInFill )
+ {
+ if ( nThisOther > nFillStart ) // ist was zu verteilen da?
+ {
+ SCTAB nDiff1 = nThisOther - nFillStart;
+ SCTAB nDiff2 = nThisTab - nFillPos;
+ SCTAB nMinDiff = Min(nDiff1, nDiff2);
+ for (SCTAB i=0; i<nMinDiff; i++)
+ if ( !IsScenario(nFillPos+i) && !rOtherDoc.IsScenario(nFillStart+i) )
+ pOtherTabs[nFillPos+i] = nFillStart+i;
+ }
+
+ bInFill = FALSE;
+ }
+ nFillStart = nThisOther + 1;
+ nFillPos = nThisTab + 1;
+ }
+ else
+ bInFill = TRUE;
+ }
+
+ //
+ // Tabellen in der gefundenen Reihenfolge vergleichen
+ //
+
+ for (nThisTab=0; nThisTab<nThisCount; nThisTab++)
+ {
+ SCTAB nOtherTab = pOtherTabs[nThisTab];
+ if ( ValidTab(nOtherTab) )
+ {
+ SCCOL nThisEndCol = 0;
+ SCROW nThisEndRow = 0;
+ SCCOL nOtherEndCol = 0;
+ SCROW nOtherEndRow = 0;
+ GetCellArea( nThisTab, nThisEndCol, nThisEndRow );
+ rOtherDoc.GetCellArea( nOtherTab, nOtherEndCol, nOtherEndRow );
+ SCCOL nEndCol = Max(nThisEndCol, nOtherEndCol);
+ SCROW nEndRow = Max(nThisEndRow, nOtherEndRow);
+ SCCOL nThisCol;
+ SCROW nThisRow;
+ ULONG n1,n2; // fuer AppendDeleteRange
+
+ //! ein Progress ueber alle Tabellen ???
+ String aTabName;
+ GetName( nThisTab, aTabName );
+ String aTemplate = ScGlobal::GetRscString(STR_PROGRESS_COMPARING);
+ String aProText = aTemplate.GetToken( 0, '#' );
+ aProText += aTabName;
+ aProText += aTemplate.GetToken( 1, '#' );
+ ScProgress aProgress( GetDocumentShell(),
+ aProText, 3*nThisEndRow ); // 2x FindOrder, 1x hier
+ long nProgressStart = 2*nThisEndRow; // start fuer hier
+
+ SCCOLROW* pTempRows = new SCCOLROW[nThisEndRow+1];
+ SCCOLROW* pOtherRows = new SCCOLROW[nThisEndRow+1];
+ SCCOLROW* pOtherCols = new SCCOLROW[nThisEndCol+1];
+
+ // eingefuegte/geloeschte Spalten/Zeilen finden:
+ // Zwei Versuche:
+ // 1) Original Zeilen vergleichen (pTempRows)
+ // 2) Original Spalten vergleichen (pOtherCols)
+ // mit dieser Spaltenreihenfolge Zeilen vergleichen (pOtherRows)
+
+ //! Spalten vergleichen zweimal mit unterschiedlichem nMinGood ???
+
+ // 1
+ FindOrder( pTempRows, nThisEndRow, nOtherEndRow, FALSE,
+ rOtherDoc, nThisTab, nOtherTab, nEndCol, NULL, &aProgress, 0 );
+ // 2
+ FindOrder( pOtherCols, nThisEndCol, nOtherEndCol, TRUE,
+ rOtherDoc, nThisTab, nOtherTab, nEndRow, NULL, NULL, 0 );
+ FindOrder( pOtherRows, nThisEndRow, nOtherEndRow, FALSE,
+ rOtherDoc, nThisTab, nOtherTab, nThisEndCol,
+ pOtherCols, &aProgress, nThisEndRow );
+
+ ULONG nMatch1 = 0; // pTempRows, keine Spalten
+ for (nThisRow = 0; nThisRow<=nThisEndRow; nThisRow++)
+ if (ValidRow(pTempRows[nThisRow]))
+ nMatch1 += SC_DOCCOMP_MAXDIFF -
+ RowDifferences( nThisRow, nThisTab, rOtherDoc, pTempRows[nThisRow],
+ nOtherTab, nEndCol, NULL );
+
+ ULONG nMatch2 = 0; // pOtherRows, pOtherCols
+ for (nThisRow = 0; nThisRow<=nThisEndRow; nThisRow++)
+ if (ValidRow(pOtherRows[nThisRow]))
+ nMatch2 += SC_DOCCOMP_MAXDIFF -
+ RowDifferences( nThisRow, nThisTab, rOtherDoc, pOtherRows[nThisRow],
+ nOtherTab, nThisEndCol, pOtherCols );
+
+ if ( nMatch1 >= nMatch2 ) // ohne Spalten ?
+ {
+ // Spalten zuruecksetzen
+ for (nThisCol = 0; nThisCol<=nThisEndCol; nThisCol++)
+ pOtherCols[nThisCol] = nThisCol;
+
+ // Zeilenarrays vertauschen (geloescht werden sowieso beide)
+ SCCOLROW* pSwap = pTempRows;
+ pTempRows = pOtherRows;
+ pOtherRows = pSwap;
+ }
+ else
+ {
+ // bleibt bei pOtherCols, pOtherRows
+ }
+
+
+ // Change-Actions erzeugen
+ // 1) Spalten von rechts
+ // 2) Zeilen von unten
+ // 3) einzelne Zellen in normaler Reihenfolge
+
+ // Actions fuer eingefuegte/geloeschte Spalten
+
+ SCCOL nLastOtherCol = static_cast<SCCOL>(nOtherEndCol + 1);
+ // nThisEndCol ... 0
+ for ( nThisCol = nThisEndCol+1; nThisCol > 0; )
+ {
+ --nThisCol;
+ SCCOL nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
+ if ( ValidCol(nOtherCol) && nOtherCol+1 < nLastOtherCol )
+ {
+ // Luecke -> geloescht
+ ScRange aDelRange( nOtherCol+1, 0, nOtherTab,
+ nLastOtherCol-1, MAXROW, nOtherTab );
+ pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
+ }
+ if ( nOtherCol > MAXCOL ) // eingefuegt
+ {
+ // zusammenfassen
+ if ( nThisCol == nThisEndCol || ValidCol(static_cast<SCCOL>(pOtherCols[nThisCol+1])) )
+ {
+ SCCOL nFirstNew = static_cast<SCCOL>(nThisCol);
+ while ( nFirstNew > 0 && pOtherCols[nFirstNew-1] > MAXCOL )
+ --nFirstNew;
+ SCCOL nDiff = nThisCol - nFirstNew;
+ ScRange aRange( nLastOtherCol, 0, nOtherTab,
+ nLastOtherCol+nDiff, MAXROW, nOtherTab );
+ pChangeTrack->AppendInsert( aRange );
+ }
+ }
+ else
+ nLastOtherCol = nOtherCol;
+ }
+ if ( nLastOtherCol > 0 ) // ganz oben geloescht
+ {
+ ScRange aDelRange( 0, 0, nOtherTab,
+ nLastOtherCol-1, MAXROW, nOtherTab );
+ pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
+ }
+
+ // Actions fuer eingefuegte/geloeschte Zeilen
+
+ SCROW nLastOtherRow = nOtherEndRow + 1;
+ // nThisEndRow ... 0
+ for ( nThisRow = nThisEndRow+1; nThisRow > 0; )
+ {
+ --nThisRow;
+ SCROW nOtherRow = pOtherRows[nThisRow];
+ if ( ValidRow(nOtherRow) && nOtherRow+1 < nLastOtherRow )
+ {
+ // Luecke -> geloescht
+ ScRange aDelRange( 0, nOtherRow+1, nOtherTab,
+ MAXCOL, nLastOtherRow-1, nOtherTab );
+ pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
+ }
+ if ( nOtherRow > MAXROW ) // eingefuegt
+ {
+ // zusammenfassen
+ if ( nThisRow == nThisEndRow || ValidRow(pOtherRows[nThisRow+1]) )
+ {
+ SCROW nFirstNew = nThisRow;
+ while ( nFirstNew > 0 && pOtherRows[nFirstNew-1] > MAXROW )
+ --nFirstNew;
+ SCROW nDiff = nThisRow - nFirstNew;
+ ScRange aRange( 0, nLastOtherRow, nOtherTab,
+ MAXCOL, nLastOtherRow+nDiff, nOtherTab );
+ pChangeTrack->AppendInsert( aRange );
+ }
+ }
+ else
+ nLastOtherRow = nOtherRow;
+ }
+ if ( nLastOtherRow > 0 ) // ganz oben geloescht
+ {
+ ScRange aDelRange( 0, 0, nOtherTab,
+ MAXCOL, nLastOtherRow-1, nOtherTab );
+ pChangeTrack->AppendDeleteRange( aDelRange, &rOtherDoc, n1, n2 );
+ }
+
+ // Zeilen durchgehen um einzelne Zellen zu finden
+
+ for (nThisRow = 0; nThisRow <= nThisEndRow; nThisRow++)
+ {
+ SCROW nOtherRow = pOtherRows[nThisRow];
+ for (nThisCol = 0; nThisCol <= nThisEndCol; nThisCol++)
+ {
+ SCCOL nOtherCol = static_cast<SCCOL>(pOtherCols[nThisCol]);
+ ScAddress aThisPos( nThisCol, nThisRow, nThisTab );
+ const ScBaseCell* pThisCell = GetCell( aThisPos );
+ const ScBaseCell* pOtherCell = NULL;
+ if ( ValidCol(nOtherCol) && ValidRow(nOtherRow) )
+ {
+ ScAddress aOtherPos( nOtherCol, nOtherRow, nOtherTab );
+ pOtherCell = rOtherDoc.GetCell( aOtherPos );
+ }
+ if ( !ScBaseCell::CellEqual( pThisCell, pOtherCell ) )
+ {
+ ScRange aRange( aThisPos );
+ ScChangeActionContent* pAction = new ScChangeActionContent( aRange );
+ pAction->SetOldValue( pOtherCell, &rOtherDoc, this );
+ pAction->SetNewValue( pThisCell, this );
+ pChangeTrack->Append( pAction );
+ }
+ }
+ aProgress.SetStateOnPercent(nProgressStart+nThisRow);
+ }
+
+ delete[] pOtherCols;
+ delete[] pOtherRows;
+ delete[] pTempRows;
+ }
+ }
+
+ //! Inhalt von eingefuegten / geloeschten Tabellen ???
+ //! Aktionen fuer eingefuegte / geloeschte Tabellen ???
+
+ delete[] pOtherTabs;
+}
+
+
+
+
+
diff --git a/sc/source/core/data/documen5.cxx b/sc/source/core/data/documen5.cxx
new file mode 100644
index 000000000000..8d528db34118
--- /dev/null
+++ b/sc/source/core/data/documen5.cxx
@@ -0,0 +1,1014 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: documen5.cxx,v $
+ * $Revision: 1.34 $
+ *
+ * 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 <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/chart2/data/XDataProvider.hpp>
+#include <com/sun/star/chart2/data/XDataReceiver.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+
+#ifdef _MSC_VER
+#pragma optimize("",off)
+#endif
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <sfx2/objsh.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+
+//REMOVE #ifndef SO2_DECL_SVINPLACEOBJECT_DEFINED
+//REMOVE #define SO2_DECL_SVINPLACEOBJECT_DEFINED
+//REMOVE SO2_DECL_REF(SvInPlaceObject)
+//REMOVE #endif
+
+#include "document.hxx"
+#include "drwlayer.hxx"
+#include "chartarr.hxx"
+#include "chartlis.hxx"
+#include "chartlock.hxx"
+#include "refupdat.hxx"
+#include <tools/globname.hxx>
+#include <sot/exchange.hxx>
+
+#include "miscuno.hxx"
+#include "chart2uno.hxx"
+
+using namespace ::com::sun::star;
+
+// -----------------------------------------------------------------------
+
+void lcl_GetChartRanges( const uno::Reference< chart2::XChartDocument >& xChartDoc,
+ uno::Sequence< rtl::OUString >& rRanges )
+{
+ rRanges.realloc(0);
+ uno::Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY );
+ if( !xDataSource.is() )
+ return;
+ //uno::Reference< chart2::data::XDataProvider > xProvider = xChartDoc->getDataProvider();
+
+ uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledDataSequences( xDataSource->getDataSequences() );
+ rRanges.realloc(2*aLabeledDataSequences.getLength());
+ sal_Int32 nRealCount=0;
+ for( sal_Int32 nN=0;nN<aLabeledDataSequences.getLength();nN++)
+ {
+ uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSequence( aLabeledDataSequences[nN] );
+ if(!xLabeledSequence.is())
+ continue;
+ uno::Reference< chart2::data::XDataSequence > xLabel( xLabeledSequence->getLabel());
+ uno::Reference< chart2::data::XDataSequence > xValues( xLabeledSequence->getValues());
+
+ if( xLabel.is())
+ rRanges[nRealCount++] = xLabel->getSourceRangeRepresentation();
+ if( xValues.is())
+ rRanges[nRealCount++] = xValues->getSourceRangeRepresentation();
+ }
+ rRanges.realloc(nRealCount);
+}
+
+void lcl_SetChartRanges( const uno::Reference< chart2::XChartDocument >& xChartDoc,
+ const uno::Sequence< rtl::OUString >& rRanges )
+{
+ uno::Reference< chart2::data::XDataSource > xDataSource( xChartDoc, uno::UNO_QUERY );
+ if( !xDataSource.is() )
+ return;
+ uno::Reference< chart2::data::XDataProvider > xDataProvider = xChartDoc->getDataProvider();
+ if( !xDataProvider.is() )
+ return;
+
+ uno::Reference< frame::XModel > xModel( xChartDoc, uno::UNO_QUERY );
+ if( xModel.is() )
+ xModel->lockControllers();
+
+ try
+ {
+ rtl::OUString aPropertyNameRole( ::rtl::OUString::createFromAscii("Role") );
+
+ uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aLabeledDataSequences( xDataSource->getDataSequences() );
+ sal_Int32 nRange=0;
+ for( sal_Int32 nN=0; (nN<aLabeledDataSequences.getLength()) && (nRange<rRanges.getLength()); nN++ )
+ {
+ uno::Reference< chart2::data::XLabeledDataSequence > xLabeledSequence( aLabeledDataSequences[nN] );
+ if(!xLabeledSequence.is())
+ continue;
+ uno::Reference< beans::XPropertySet > xLabel( xLabeledSequence->getLabel(), uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySet > xValues( xLabeledSequence->getValues(), uno::UNO_QUERY );
+
+ if( xLabel.is())
+ {
+ uno::Reference< chart2::data::XDataSequence > xNewSeq(
+ xDataProvider->createDataSequenceByRangeRepresentation( rRanges[nRange++] ));
+
+ uno::Reference< beans::XPropertySet > xNewProps( xNewSeq, uno::UNO_QUERY );
+ if( xNewProps.is() )
+ xNewProps->setPropertyValue( aPropertyNameRole, xLabel->getPropertyValue( aPropertyNameRole ) );
+
+ xLabeledSequence->setLabel( xNewSeq );
+ }
+
+ if( !(nRange<rRanges.getLength()) )
+ break;
+
+ if( xValues.is())
+ {
+ uno::Reference< chart2::data::XDataSequence > xNewSeq(
+ xDataProvider->createDataSequenceByRangeRepresentation( rRanges[nRange++] ));
+
+ uno::Reference< beans::XPropertySet > xNewProps( xNewSeq, uno::UNO_QUERY );
+ if( xNewProps.is() )
+ xNewProps->setPropertyValue( aPropertyNameRole, xValues->getPropertyValue( aPropertyNameRole ) );
+
+ xLabeledSequence->setValues( xNewSeq );
+ }
+ }
+ }
+ catch ( uno::Exception& ex )
+ {
+ (void)ex;
+ DBG_ERROR("Exception in lcl_SetChartRanges - invalid range string?");
+ }
+
+ if( xModel.is() )
+ xModel->unlockControllers();
+}
+
+void lcl_GetChartParameters( const uno::Reference< chart2::XChartDocument >& xChartDoc,
+ rtl::OUString& rRanges, chart::ChartDataRowSource& rDataRowSource,
+ bool& rHasCategories, bool& rFirstCellAsLabel )
+{
+ rHasCategories = rFirstCellAsLabel = false; // default if not in sequence
+
+ uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, uno::UNO_QUERY );
+
+ uno::Reference< chart2::data::XDataSource > xDataSource = xReceiver->getUsedData();
+ uno::Reference< chart2::data::XDataProvider > xProvider = xChartDoc->getDataProvider();
+
+ if ( xProvider.is() )
+ {
+ uno::Sequence< beans::PropertyValue > aArgs( xProvider->detectArguments( xDataSource ) );
+
+ const beans::PropertyValue* pPropArray = aArgs.getConstArray();
+ long nPropCount = aArgs.getLength();
+ for (long i = 0; i < nPropCount; i++)
+ {
+ const beans::PropertyValue& rProp = pPropArray[i];
+ String aPropName(rProp.Name);
+
+ if (aPropName.EqualsAscii( "CellRangeRepresentation" ))
+ rProp.Value >>= rRanges;
+ else if (aPropName.EqualsAscii( "DataRowSource" ))
+ rDataRowSource = (chart::ChartDataRowSource)ScUnoHelpFunctions::GetEnumFromAny( rProp.Value );
+ else if (aPropName.EqualsAscii( "HasCategories" ))
+ rHasCategories = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName.EqualsAscii( "FirstCellAsLabel" ))
+ rFirstCellAsLabel = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ }
+ }
+}
+
+void lcl_SetChartParameters( const uno::Reference< chart2::data::XDataReceiver >& xReceiver,
+ const rtl::OUString& rRanges, chart::ChartDataRowSource eDataRowSource,
+ bool bHasCategories, bool bFirstCellAsLabel )
+{
+ if ( xReceiver.is() )
+ {
+ uno::Sequence< beans::PropertyValue > aArgs( 4 );
+ aArgs[0] = beans::PropertyValue(
+ ::rtl::OUString::createFromAscii("CellRangeRepresentation"), -1,
+ uno::makeAny( rRanges ), beans::PropertyState_DIRECT_VALUE );
+ aArgs[1] = beans::PropertyValue(
+ ::rtl::OUString::createFromAscii("HasCategories"), -1,
+ uno::makeAny( bHasCategories ), beans::PropertyState_DIRECT_VALUE );
+ aArgs[2] = beans::PropertyValue(
+ ::rtl::OUString::createFromAscii("FirstCellAsLabel"), -1,
+ uno::makeAny( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE );
+ aArgs[3] = beans::PropertyValue(
+ ::rtl::OUString::createFromAscii("DataRowSource"), -1,
+ uno::makeAny( eDataRowSource ), beans::PropertyState_DIRECT_VALUE );
+ xReceiver->setArguments( aArgs );
+ }
+}
+
+// update charts after loading old document
+
+void ScDocument::UpdateAllCharts()
+{
+ if ( !pDrawLayer || !pShell )
+ return;
+
+ USHORT nDataCount = pChartCollection->GetCount();
+ if ( !nDataCount )
+ return ; // nothing to do
+
+ USHORT nPos;
+
+ for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
+ {
+ if (pTab[nTab])
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ ScRange aRange;
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
+ {
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pObject)->GetObjRef();
+ if ( xIPObj.is() )
+ {
+ String aIPName = ((SdrOle2Obj*)pObject)->GetPersistName();
+
+ for (nPos=0; nPos<nDataCount; nPos++)
+ {
+ ScChartArray* pChartObj = (*pChartCollection)[nPos];
+ if (pChartObj->GetName() == aIPName)
+ {
+ ScRangeListRef aRanges = pChartObj->GetRangeList();
+ String sRangeStr;
+ aRanges->Format( sRangeStr, SCR_ABS_3D, this, GetAddressConvention() );
+
+ chart::ChartDataRowSource eDataRowSource = chart::ChartDataRowSource_COLUMNS;
+ bool bHasCategories = pChartObj->HasRowHeaders();
+ bool bFirstCellAsLabel = pChartObj->HasColHeaders();
+
+ // Calc -> DataProvider
+ uno::Reference< chart2::data::XDataProvider > xDataProvider =
+ new ScChart2DataProvider( this );
+ // Chart -> DataReceiver
+ uno::Reference< chart2::data::XDataReceiver > xReceiver;
+ uno::Reference< embed::XComponentSupplier > xCompSupp( xIPObj, uno::UNO_QUERY );
+ if( xCompSupp.is())
+ xReceiver.set( xCompSupp->getComponent(), uno::UNO_QUERY );
+ if( xReceiver.is())
+ {
+ // connect
+ xReceiver->attachDataProvider( xDataProvider );
+ uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier(
+ pShell->GetModel(), uno::UNO_QUERY );
+ xReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier );
+
+ lcl_SetChartParameters( xReceiver, sRangeStr, eDataRowSource,
+ bHasCategories, bFirstCellAsLabel );
+ }
+
+ ScChartListener* pCL = new ScChartListener(
+ aIPName, this, pChartObj->GetRangeList() );
+ pChartListenerCollection->Insert( pCL );
+ pCL->StartListeningTo();
+ }
+ }
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+
+ pChartCollection->FreeAll();
+}
+
+BOOL ScDocument::HasChartAtPoint( SCTAB nTab, const Point& rPos, String* pName )
+{
+ if (pDrawLayer && pTab[nTab])
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ pObject->GetCurrentBoundRect().IsInside(rPos) )
+ {
+ // auch Chart-Objekte die nicht in der Collection sind
+
+ if (IsChart(pObject))
+ {
+ if (pName)
+ *pName = ((SdrOle2Obj*)pObject)->GetPersistName();
+ return TRUE;
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+
+ if (pName)
+ pName->Erase();
+ return FALSE; // nix gefunden
+}
+
+void ScDocument::UpdateChartArea( const String& rChartName,
+ const ScRange& rNewArea, BOOL bColHeaders, BOOL bRowHeaders,
+ BOOL bAdd )
+{
+ ScRangeListRef aRLR( new ScRangeList );
+ aRLR->Append( rNewArea );
+ UpdateChartArea( rChartName, aRLR, bColHeaders, bRowHeaders, bAdd );
+}
+
+uno::Reference< chart2::XChartDocument > ScDocument::GetChartByName( const String& rChartName )
+{
+ uno::Reference< chart2::XChartDocument > xReturn;
+
+ if (pDrawLayer)
+ {
+ sal_uInt16 nCount = pDrawLayer->GetPageCount();
+ for (sal_uInt16 nTab=0; nTab<nCount; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(nTab);
+ DBG_ASSERT(pPage,"Page ?");
+
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ ((SdrOle2Obj*)pObject)->GetPersistName() == rChartName )
+ {
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pObject)->GetObjRef();
+ if ( xIPObj.is() )
+ {
+ svt::EmbeddedObjectRef::TryRunningState( xIPObj );
+
+ uno::Reference< util::XCloseable > xComponent = xIPObj->getComponent();
+ xReturn.set( uno::Reference< chart2::XChartDocument >( xComponent, uno::UNO_QUERY ) );
+ }
+ return xReturn;
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ return xReturn;
+}
+void ScDocument::GetChartRanges( const String& rChartName, ::std::vector< ScRangeList >& rRangesVector, ScDocument* pSheetNameDoc )
+{
+ rRangesVector.clear();
+ uno::Reference< chart2::XChartDocument > xChartDoc( GetChartByName( rChartName ) );
+ if ( xChartDoc.is() )
+ {
+ uno::Sequence< rtl::OUString > aRangeStrings;
+ lcl_GetChartRanges( xChartDoc, aRangeStrings );
+ for( sal_Int32 nN=0; nN<aRangeStrings.getLength(); nN++ )
+ {
+ ScRangeList aRanges;
+ aRanges.Parse( aRangeStrings[nN], pSheetNameDoc );
+ rRangesVector.push_back(aRanges);
+ }
+ }
+}
+
+void ScDocument::SetChartRanges( const String& rChartName, const ::std::vector< ScRangeList >& rRangesVector )
+{
+ uno::Reference< chart2::XChartDocument > xChartDoc( GetChartByName( rChartName ) );
+ if ( xChartDoc.is() )
+ {
+ sal_Int32 nCount = static_cast<sal_Int32>( rRangesVector.size() );
+ uno::Sequence< rtl::OUString > aRangeStrings(nCount);
+ for( sal_Int32 nN=0; nN<nCount; nN++ )
+ {
+ ScRangeList aScRangeList( rRangesVector[nN] );
+ String sRangeStr;
+ aScRangeList.Format( sRangeStr, SCR_ABS_3D, this, GetAddressConvention() );
+ aRangeStrings[nN]=sRangeStr;
+ }
+ lcl_SetChartRanges( xChartDoc, aRangeStrings );
+ }
+}
+
+void ScDocument::GetOldChartParameters( const String& rName,
+ ScRangeList& rRanges, BOOL& rColHeaders, BOOL& rRowHeaders )
+{
+ // used for undo of changing chart source area
+
+ if (!pDrawLayer)
+ return;
+
+ sal_uInt16 nCount = pDrawLayer->GetPageCount();
+ for (sal_uInt16 nTab=0; nTab<nCount; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(nTab);
+ DBG_ASSERT(pPage,"Page ?");
+
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ ((SdrOle2Obj*)pObject)->GetPersistName() == rName )
+ {
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pObject)->GetObjRef();
+ if ( xIPObj.is() )
+ {
+ svt::EmbeddedObjectRef::TryRunningState( xIPObj );
+
+ uno::Reference< util::XCloseable > xComponent = xIPObj->getComponent();
+ uno::Reference< chart2::XChartDocument > xChartDoc( xComponent, uno::UNO_QUERY );
+ if ( xChartDoc.is() )
+ {
+ chart::ChartDataRowSource eDataRowSource = chart::ChartDataRowSource_COLUMNS;
+ bool bHasCategories = false;
+ bool bFirstCellAsLabel = false;
+ rtl::OUString aRangesStr;
+ lcl_GetChartParameters( xChartDoc, aRangesStr, eDataRowSource, bHasCategories, bFirstCellAsLabel );
+
+ rRanges.Parse( aRangesStr, this );
+ if ( eDataRowSource == chart::ChartDataRowSource_COLUMNS )
+ {
+ rRowHeaders = bHasCategories;
+ rColHeaders = bFirstCellAsLabel;
+ }
+ else
+ {
+ rColHeaders = bHasCategories;
+ rRowHeaders = bFirstCellAsLabel;
+ }
+ }
+ }
+ return;
+ }
+ pObject = aIter.Next();
+ }
+ }
+}
+
+void ScDocument::UpdateChartArea( const String& rChartName,
+ const ScRangeListRef& rNewList, BOOL bColHeaders, BOOL bRowHeaders,
+ BOOL bAdd )
+{
+ if (!pDrawLayer)
+ return;
+
+ for (SCTAB nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ ((SdrOle2Obj*)pObject)->GetPersistName() == rChartName )
+ {
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pObject)->GetObjRef();
+ if ( xIPObj.is() )
+ {
+ svt::EmbeddedObjectRef::TryRunningState( xIPObj );
+
+ uno::Reference< util::XCloseable > xComponent = xIPObj->getComponent();
+ uno::Reference< chart2::XChartDocument > xChartDoc( xComponent, uno::UNO_QUERY );
+ uno::Reference< chart2::data::XDataReceiver > xReceiver( xComponent, uno::UNO_QUERY );
+ if ( xChartDoc.is() && xReceiver.is() )
+ {
+ ScRangeListRef aNewRanges;
+ chart::ChartDataRowSource eDataRowSource = chart::ChartDataRowSource_COLUMNS;
+ bool bHasCategories = false;
+ bool bFirstCellAsLabel = false;
+ rtl::OUString aRangesStr;
+ lcl_GetChartParameters( xChartDoc, aRangesStr, eDataRowSource, bHasCategories, bFirstCellAsLabel );
+
+ sal_Bool bInternalData = xChartDoc->hasInternalDataProvider();
+
+ if ( bAdd && !bInternalData )
+ {
+ // append to old ranges, keep other settings
+
+ aNewRanges = new ScRangeList;
+ aNewRanges->Parse( aRangesStr, this );
+
+ ULONG nAddCount = rNewList->Count();
+ for ( ULONG nAdd=0; nAdd<nAddCount; nAdd++ )
+ aNewRanges->Append( *rNewList->GetObject(nAdd) );
+ }
+ else
+ {
+ // directly use new ranges (only eDataRowSource is used from old settings)
+
+ if ( eDataRowSource == chart::ChartDataRowSource_COLUMNS )
+ {
+ bHasCategories = bRowHeaders;
+ bFirstCellAsLabel = bColHeaders;
+ }
+ else
+ {
+ bHasCategories = bColHeaders;
+ bFirstCellAsLabel = bRowHeaders;
+ }
+ aNewRanges = rNewList;
+ }
+
+ if ( bInternalData && pShell )
+ {
+ // Calc -> DataProvider
+ uno::Reference< chart2::data::XDataProvider > xDataProvider = new ScChart2DataProvider( this );
+ xReceiver->attachDataProvider( xDataProvider );
+ uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier(
+ pShell->GetModel(), uno::UNO_QUERY );
+ xReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier );
+ }
+
+ String sRangeStr;
+ aNewRanges->Format( sRangeStr, SCR_ABS_3D, this, GetAddressConvention() );
+
+ lcl_SetChartParameters( xReceiver, sRangeStr, eDataRowSource, bHasCategories, bFirstCellAsLabel );
+
+ pChartListenerCollection->ChangeListening( rChartName, aNewRanges );
+
+ // ((SdrOle2Obj*)pObject)->GetNewReplacement();
+ // pObject->ActionChanged();
+
+ return; // nicht weitersuchen
+ }
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+}
+
+void ScDocument::UpdateChart( const String& rChartName )
+{
+ if (!pDrawLayer || bInDtorClear)
+ return;
+
+ for (SCTAB nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ ((SdrOle2Obj*)pObject)->GetPersistName() == rChartName )
+ {
+ //@todo?: maybe we need a notification
+ //from the calc to the chart in future
+ //that calc content has changed
+ // ((SdrOle2Obj*)pObject)->GetNewReplacement();
+
+ // Load the object and set modified
+
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pObject)->GetObjRef();
+ if ( xIPObj.is() )
+ {
+ svt::EmbeddedObjectRef::TryRunningState( xIPObj );
+
+ try
+ {
+ uno::Reference< util::XModifiable > xModif( xIPObj->getComponent(), uno::UNO_QUERY_THROW );
+ if( apTemporaryChartLock.get() )
+ apTemporaryChartLock->AlsoLockThisChart( uno::Reference< frame::XModel >( xModif, uno::UNO_QUERY ) );
+ xModif->setModified( sal_True );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+
+ // repaint
+
+ pObject->ActionChanged();
+
+ // After the update, chart keeps track of its own data source ranges,
+ // the listener doesn't need to listen anymore.
+
+ pChartListenerCollection->ChangeListening( rChartName, new ScRangeList );
+
+ return;
+
+ /* old chart:
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pObject)->GetObjRef();
+ if ( xIPObj.is() )
+ {
+ const SchMemChart* pChartData = SchDLL::GetChartData(xIPObj);
+ if ( pChartData )
+ {
+ ScChartArray aArray( this, *pChartData );
+
+ SchMemChart* pMemChart = aArray.CreateMemChart();
+ ScChartArray::CopySettings( *pMemChart, *pChartData );
+
+ // #57655# Chart-Update ohne geaenderte Einstellungen (MemChart)
+ // soll das Dokument nicht auf modified setzen (z.B. in frisch
+ // geladenem Dokument durch initiales Recalc)
+
+ // #72576# disable SetModified for readonly documents only
+
+ sal_Bool bEnabled = ( (pShell && pShell->IsReadOnly()) || IsImportingXML() );
+ sal_Bool bModified = sal_False;
+ uno::Reference< util::XModifiable > xModif;
+
+ if ( bEnabled )
+ {
+ try
+ {
+ xModif =
+ uno::Reference< util::XModifiable >( xIPObj->getComponent(), uno::UNO_QUERY_THROW );
+ bModified = xModif->isModified();
+ }
+ catch( uno::Exception& )
+ {
+ bEnabled = sal_False;
+ }
+ }
+
+ SchDLL::Update( xIPObj, pMemChart, pWindow );
+ ((SdrOle2Obj*)pObject)->GetNewReplacement();
+ delete pMemChart;
+
+ // Dies veranlaesst Chart zum sofortigen Update
+ //SvData aEmpty;
+ //aIPObj->SendDataChanged( aEmpty );
+
+ // the method below did nothing in SO7
+//REMOVE aIPObj->SendViewChanged();
+
+ // redraw only
+ pObject->ActionChanged();
+ // pObject->SendRepaintBroadcast();
+
+ if ( bEnabled && xModif.is() )
+ {
+ try
+ {
+ if ( xModif->isModified() != bModified )
+ xModif->setModified( bModified );
+ }
+ catch ( uno::Exception& )
+ {}
+ }
+
+ return; // nicht weitersuchen
+ }
+ }
+ */
+ }
+ pObject = aIter.Next();
+ }
+ }
+}
+
+void ScDocument::RestoreChartListener( const String& rName )
+{
+ // Read the data ranges from the chart object, and start listening to those ranges again
+ // (called when a chart is saved, because then it might be swapped out and stop listening itself).
+
+ uno::Reference< embed::XEmbeddedObject > xObject = FindOleObjectByName( rName );
+ if ( xObject.is() )
+ {
+ uno::Reference< util::XCloseable > xComponent = xObject->getComponent();
+ uno::Reference< chart2::XChartDocument > xChartDoc( xComponent, uno::UNO_QUERY );
+ uno::Reference< chart2::data::XDataReceiver > xReceiver( xComponent, uno::UNO_QUERY );
+ if ( xChartDoc.is() && xReceiver.is() && !xChartDoc->hasInternalDataProvider())
+ {
+ uno::Sequence<rtl::OUString> aRepresentations( xReceiver->getUsedRangeRepresentations() );
+ ScRangeListRef aRanges = new ScRangeList;
+ sal_Int32 nRangeCount = aRepresentations.getLength();
+ for ( sal_Int32 i=0; i<nRangeCount; i++ )
+ {
+ ScRange aRange;
+ ScAddress::Details aDetails(GetAddressConvention(), 0, 0);
+ if ( aRange.ParseAny( aRepresentations[i], this, aDetails ) & SCA_VALID )
+ aRanges->Append( aRange );
+ }
+
+ pChartListenerCollection->ChangeListening( rName, aRanges );
+ }
+ }
+}
+
+void ScDocument::UpdateChartRef( UpdateRefMode eUpdateRefMode,
+ SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ if (!pDrawLayer)
+ return;
+
+ USHORT nChartCount = pChartListenerCollection->GetCount();
+ for ( USHORT nIndex = 0; nIndex < nChartCount; nIndex++ )
+ {
+ ScChartListener* pChartListener =
+ (ScChartListener*) (pChartListenerCollection->At(nIndex));
+ ScRangeListRef aRLR( pChartListener->GetRangeList() );
+ ScRangeListRef aNewRLR( new ScRangeList );
+ BOOL bChanged = FALSE;
+ BOOL bDataChanged = FALSE;
+ for ( ScRangePtr pR = aRLR->First(); pR; pR = aRLR->Next() )
+ {
+ SCCOL theCol1 = pR->aStart.Col();
+ SCROW theRow1 = pR->aStart.Row();
+ SCTAB theTab1 = pR->aStart.Tab();
+ SCCOL theCol2 = pR->aEnd.Col();
+ SCROW theRow2 = pR->aEnd.Row();
+ SCTAB theTab2 = pR->aEnd.Tab();
+ ScRefUpdateRes eRes = ScRefUpdate::Update(
+ this, eUpdateRefMode,
+ nCol1,nRow1,nTab1, nCol2,nRow2,nTab2,
+ nDx,nDy,nDz,
+ theCol1,theRow1,theTab1,
+ theCol2,theRow2,theTab2 );
+ if ( eRes != UR_NOTHING )
+ {
+ bChanged = TRUE;
+ aNewRLR->Append( ScRange(
+ theCol1, theRow1, theTab1,
+ theCol2, theRow2, theTab2 ));
+ if ( eUpdateRefMode == URM_INSDEL
+ && !bDataChanged
+ && (eRes == UR_INVALID ||
+ ((pR->aEnd.Col() - pR->aStart.Col()
+ != theCol2 - theCol1)
+ || (pR->aEnd.Row() - pR->aStart.Row()
+ != theRow2 - theRow1)
+ || (pR->aEnd.Tab() - pR->aStart.Tab()
+ != theTab2 - theTab1))) )
+ {
+ bDataChanged = TRUE;
+ }
+ }
+ else
+ aNewRLR->Append( *pR );
+ }
+ if ( bChanged )
+ {
+#if 0
+ if ( nDz != 0 )
+ { // #81844# sheet to be deleted or inserted or moved
+ // => no valid sheet names for references right now
+ pChartListener->ChangeListening( aNewRLR, bDataChanged );
+ pChartListener->ScheduleSeriesRanges();
+ }
+ else
+#endif
+ {
+// SetChartRangeList( pChartListener->GetString(), aNewRLR );
+// pChartListener->ChangeListening( aNewRLR, bDataChanged );
+
+ // Force the chart to be loaded now, so it registers itself for UNO events.
+ // UNO broadcasts are done after UpdateChartRef, so the chart will get this
+ // reference change.
+
+ uno::Reference< embed::XEmbeddedObject > xIPObj = FindOleObjectByName( pChartListener->GetString() );
+ svt::EmbeddedObjectRef::TryRunningState( xIPObj );
+
+ // After the change, chart keeps track of its own data source ranges,
+ // the listener doesn't need to listen anymore.
+
+ pChartListener->ChangeListening( new ScRangeList, bDataChanged );
+ }
+ }
+ }
+}
+
+
+void ScDocument::SetChartRangeList( const String& rChartName,
+ const ScRangeListRef& rNewRangeListRef )
+{
+ // called from ChartListener
+
+ if (!pDrawLayer)
+ return;
+
+ for (SCTAB nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ ((SdrOle2Obj*)pObject)->GetPersistName() == rChartName )
+ {
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pObject)->GetObjRef();
+ if ( xIPObj.is() )
+ {
+ svt::EmbeddedObjectRef::TryRunningState( xIPObj );
+
+ uno::Reference< util::XCloseable > xComponent = xIPObj->getComponent();
+ uno::Reference< chart2::XChartDocument > xChartDoc( xComponent, uno::UNO_QUERY );
+ uno::Reference< chart2::data::XDataReceiver > xReceiver( xComponent, uno::UNO_QUERY );
+ if ( xChartDoc.is() && xReceiver.is() )
+ {
+ ScRangeListRef aNewRanges;
+ chart::ChartDataRowSource eDataRowSource = chart::ChartDataRowSource_COLUMNS;
+ bool bHasCategories = false;
+ bool bFirstCellAsLabel = false;
+ rtl::OUString aRangesStr;
+ lcl_GetChartParameters( xChartDoc, aRangesStr, eDataRowSource, bHasCategories, bFirstCellAsLabel );
+
+ String sRangeStr;
+ rNewRangeListRef->Format( sRangeStr, SCR_ABS_3D, this, GetAddressConvention() );
+
+ lcl_SetChartParameters( xReceiver, sRangeStr, eDataRowSource, bHasCategories, bFirstCellAsLabel );
+
+ // don't modify pChartListenerCollection here, called from there
+ return;
+ }
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+}
+
+
+BOOL ScDocument::HasData( SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ if (pTab[nTab])
+ return pTab[nTab]->HasData( nCol, nRow );
+ else
+ return FALSE;
+}
+
+uno::Reference< embed::XEmbeddedObject >
+ ScDocument::FindOleObjectByName( const String& rName )
+{
+ if (!pDrawLayer)
+ return uno::Reference< embed::XEmbeddedObject >();
+
+ // die Seiten hier vom Draw-Layer nehmen,
+ // weil sie evtl. nicht mit den Tabellen uebereinstimmen
+ // (z.B. Redo von Tabelle loeschen, Draw-Redo passiert vor DeleteTab).
+
+ sal_uInt16 nCount = pDrawLayer->GetPageCount();
+ for (sal_uInt16 nTab=0; nTab<nCount; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(nTab);
+ DBG_ASSERT(pPage,"Page ?");
+
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
+ {
+ SdrOle2Obj * pOleObject ( dynamic_cast< SdrOle2Obj * >( pObject ));
+ if( pOleObject &&
+ pOleObject->GetPersistName() == rName )
+ {
+ return pOleObject->GetObjRef();
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+
+ return uno::Reference< embed::XEmbeddedObject >();
+}
+
+BOOL lcl_StringInCollection( const ScStrCollection* pColl, const String& rStr )
+{
+ if ( !pColl )
+ return FALSE;
+
+ StrData aData( rStr );
+ USHORT nDummy;
+ return pColl->Search( &aData, nDummy );
+}
+
+void ScDocument::UpdateChartListenerCollection()
+{
+ bChartListenerCollectionNeedsUpdate = FALSE;
+ if (!pDrawLayer)
+ return;
+ else
+ {
+ ScRange aRange;
+ // Range fuer Suche unwichtig
+ ScChartListener aCLSearcher( EMPTY_STRING, this, aRange );
+ for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
+ {
+ if (pTab[nTab])
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 )
+ {
+ String aObjName = ((SdrOle2Obj*)pObject)->GetPersistName();
+ aCLSearcher.SetString( aObjName );
+ USHORT nIndex;
+ if ( pChartListenerCollection->Search( &aCLSearcher, nIndex ) )
+ {
+ ((ScChartListener*) (pChartListenerCollection->
+ At( nIndex )))->SetUsed( TRUE );
+ }
+ else if ( lcl_StringInCollection( pOtherObjects, aObjName ) )
+ {
+ // non-chart OLE object -> don't touch
+ }
+ else
+ {
+ bool bIsChart = false;
+
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pObject)->GetObjRef();
+ DBG_ASSERT( xIPObj.is(), "No embedded object is given!");
+ uno::Reference< ::com::sun::star::chart2::data::XDataReceiver > xReceiver;
+ uno::Reference< embed::XComponentSupplier > xCompSupp( xIPObj, uno::UNO_QUERY );
+ if( xCompSupp.is())
+ xReceiver.set( xCompSupp->getComponent(), uno::UNO_QUERY );
+
+ // if the object is a chart2::XDataReceiver, we must attach as XDataProvider
+ if( xReceiver.is() &&
+ !PastingDrawFromOtherDoc())
+ {
+ // NOTE: this currently does not work as we are
+ // unable to set the data. So a chart from the
+ // same document is treated like a chart with
+ // own data for the time being.
+#if 0
+ // data provider
+ uno::Reference< chart2::data::XDataProvider > xDataProvider = new
+ ScChart2DataProvider( this );
+ xReceiver->attachDataProvider( xDataProvider );
+ // number formats supplier
+ uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( pShell->GetModel(), uno::UNO_QUERY );
+ xReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier );
+ // data ?
+ // how to set?? Defined in XML-file, which is already loaded!!!
+ // => we have to do this stuff here, BEFORE the chart is actually loaded
+
+ bIsChart = true;
+#endif
+ }
+
+ if (!bIsChart)
+ {
+ // put into list of other ole objects, so the object doesn't have to
+ // be swapped in the next time UpdateChartListenerCollection is called
+ //! remove names when objects are no longer there?
+ // (object names aren't used again before reloading the document)
+
+ if (!pOtherObjects)
+ pOtherObjects = new ScStrCollection;
+ pOtherObjects->Insert( new StrData( aObjName ) );
+ }
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ // alle nicht auf SetUsed gesetzten loeschen
+ pChartListenerCollection->FreeUnused();
+ }
+}
+
+void ScDocument::AddOLEObjectToCollection(const String& rName)
+{
+ if (!pOtherObjects)
+ pOtherObjects = new ScStrCollection;
+ pOtherObjects->Insert( new StrData( rName ) );
+}
+
+
+
diff --git a/sc/source/core/data/documen6.cxx b/sc/source/core/data/documen6.cxx
new file mode 100644
index 000000000000..68c5655bb6c4
--- /dev/null
+++ b/sc/source/core/data/documen6.cxx
@@ -0,0 +1,187 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: documen6.cxx,v $
+ * $Revision: 1.15 $
+ *
+ * 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/scripttypeitem.hxx>
+
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include "document.hxx"
+#include "cell.hxx"
+#include "cellform.hxx"
+#include "patattr.hxx"
+#include "scrdata.hxx"
+#include "poolhelp.hxx"
+
+using namespace com::sun::star;
+
+#define SC_BREAKITER_SERVICE "com.sun.star.i18n.BreakIterator"
+
+//
+// this file is compiled with exceptions enabled
+// put functions here that need exceptions!
+//
+
+// -----------------------------------------------------------------------
+
+const uno::Reference< i18n::XBreakIterator >& ScDocument::GetBreakIterator()
+{
+ if ( !pScriptTypeData )
+ pScriptTypeData = new ScScriptTypeData;
+ if ( !pScriptTypeData->xBreakIter.is() )
+ {
+ uno::Reference< uno::XInterface > xInterface = xServiceManager->createInstance(
+ ::rtl::OUString::createFromAscii( SC_BREAKITER_SERVICE ) );
+ pScriptTypeData->xBreakIter = uno::Reference< i18n::XBreakIterator >( xInterface, uno::UNO_QUERY );
+ DBG_ASSERT( pScriptTypeData->xBreakIter.is(), "can't get BreakIterator" );
+ }
+ return pScriptTypeData->xBreakIter;
+}
+
+BOOL ScDocument::HasStringWeakCharacters( const String& rString )
+{
+ if (rString.Len())
+ {
+ uno::Reference<i18n::XBreakIterator> xBreakIter = GetBreakIterator();
+ if ( xBreakIter.is() )
+ {
+ rtl::OUString aText = rString;
+ sal_Int32 nLen = aText.getLength();
+
+ sal_Int32 nPos = 0;
+ do
+ {
+ sal_Int16 nType = xBreakIter->getScriptType( aText, nPos );
+ if ( nType == i18n::ScriptType::WEAK )
+ return TRUE; // found
+
+ nPos = xBreakIter->endOfScript( aText, nPos, nType );
+ }
+ while ( nPos >= 0 && nPos < nLen );
+ }
+ }
+
+ return FALSE; // none found
+}
+
+BYTE ScDocument::GetStringScriptType( const String& rString )
+{
+
+ BYTE nRet = 0;
+ if (rString.Len())
+ {
+ uno::Reference<i18n::XBreakIterator> xBreakIter = GetBreakIterator();
+ if ( xBreakIter.is() )
+ {
+ rtl::OUString aText = rString;
+ sal_Int32 nLen = aText.getLength();
+
+ sal_Int32 nPos = 0;
+ do
+ {
+ sal_Int16 nType = xBreakIter->getScriptType( aText, nPos );
+ switch ( nType )
+ {
+ case i18n::ScriptType::LATIN:
+ nRet |= SCRIPTTYPE_LATIN;
+ break;
+ case i18n::ScriptType::ASIAN:
+ nRet |= SCRIPTTYPE_ASIAN;
+ break;
+ case i18n::ScriptType::COMPLEX:
+ nRet |= SCRIPTTYPE_COMPLEX;
+ break;
+ // WEAK is ignored
+ }
+ nPos = xBreakIter->endOfScript( aText, nPos, nType );
+ }
+ while ( nPos >= 0 && nPos < nLen );
+ }
+ }
+ return nRet;
+}
+
+BYTE ScDocument::GetCellScriptType( ScBaseCell* pCell, ULONG nNumberFormat )
+{
+ if ( !pCell )
+ return 0; // empty
+
+ BYTE nStored = pCell->GetScriptType();
+ if ( nStored != SC_SCRIPTTYPE_UNKNOWN ) // stored value valid?
+ return nStored; // use stored value
+
+ String aStr;
+ Color* pColor;
+ ScCellFormat::GetString( pCell, nNumberFormat, aStr, &pColor, *xPoolHelper->GetFormTable() );
+
+ BYTE nRet = GetStringScriptType( aStr );
+
+ pCell->SetScriptType( nRet ); // store for later calls
+
+ return nRet;
+}
+
+BYTE ScDocument::GetScriptType( SCCOL nCol, SCROW nRow, SCTAB nTab, ScBaseCell* pCell )
+{
+ // if cell is not passed, take from document
+
+ if (!pCell)
+ {
+ pCell = GetCell( ScAddress( nCol, nRow, nTab ) );
+ if ( !pCell )
+ return 0; // empty
+ }
+
+ // if script type is set, don't have to get number formats
+
+ BYTE nStored = pCell->GetScriptType();
+ if ( nStored != SC_SCRIPTTYPE_UNKNOWN ) // stored value valid?
+ return nStored; // use stored value
+
+ // include number formats from conditional formatting
+
+ const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
+ if (!pPattern) return 0;
+ const SfxItemSet* pCondSet = NULL;
+ if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() )
+ pCondSet = GetCondResult( nCol, nRow, nTab );
+
+ ULONG nFormat = pPattern->GetNumberFormat( xPoolHelper->GetFormTable(), pCondSet );
+ return GetCellScriptType( pCell, nFormat );
+}
+
+
diff --git a/sc/source/core/data/documen7.cxx b/sc/source/core/data/documen7.cxx
new file mode 100644
index 000000000000..c0ae477ed96b
--- /dev/null
+++ b/sc/source/core/data/documen7.cxx
@@ -0,0 +1,524 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: documen7.cxx,v $
+ * $Revision: 1.12 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <vcl/svapp.hxx>
+
+#if defined( WNT ) && defined( erBEEP )
+#include <svwin.h>
+#define erBEEPER() Beep( 666, 66 )
+#else
+#define erBEEPER()
+#endif
+
+#include "document.hxx"
+#include "brdcst.hxx"
+#include "bcaslot.hxx"
+#include "cell.hxx"
+#include "formula/errorcodes.hxx" // errCircularReference
+#include "scerrors.hxx"
+#include "docoptio.hxx"
+#include "refupdat.hxx"
+#include "table.hxx"
+#include "progress.hxx"
+#include "scmod.hxx" // SC_MOD
+#include "inputopt.hxx" // GetExpandRefs
+#include "conditio.hxx"
+#include <tools/shl.hxx>
+
+
+#include "globstr.hrc"
+
+extern const ScFormulaCell* pLastFormulaTreeTop; // cellform.cxx Err527 WorkAround
+
+// STATIC DATA -----------------------------------------------------------
+
+#ifdef erDEBUG
+ULONG erCountBCAInserts = 0;
+ULONG erCountBCAFinds = 0;
+#endif
+
+// -----------------------------------------------------------------------
+
+void ScDocument::StartListeningArea( const ScRange& rRange,
+ SvtListener* pListener
+ )
+{
+ if ( pBASM )
+ pBASM->StartListeningArea( rRange, pListener );
+}
+
+
+void ScDocument::EndListeningArea( const ScRange& rRange,
+ SvtListener* pListener
+ )
+{
+ if ( pBASM )
+ pBASM->EndListeningArea( rRange, pListener );
+}
+
+
+void ScDocument::Broadcast( ULONG nHint, const ScAddress& rAddr,
+ ScBaseCell* pCell
+ )
+{
+ if ( !pBASM )
+ return ; // Clipboard or Undo
+ ScHint aHint( nHint, rAddr, pCell );
+ Broadcast( aHint );
+}
+
+
+void ScDocument::Broadcast( const ScHint& rHint )
+{
+ if ( !pBASM )
+ return ; // Clipboard or Undo
+ if ( !nHardRecalcState )
+ {
+ ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
+ BOOL bIsBroadcasted = FALSE;
+ ScBaseCell* pCell = rHint.GetCell();
+ if ( pCell )
+ {
+ SvtBroadcaster* pBC = pCell->GetBroadcaster();
+ if ( pBC )
+ {
+ pBC->Broadcast( rHint );
+ bIsBroadcasted = TRUE;
+ }
+ }
+ if ( pBASM->AreaBroadcast( rHint ) || bIsBroadcasted )
+ TrackFormulas( rHint.GetId() );
+ }
+
+ // Repaint fuer bedingte Formate mit relativen Referenzen:
+ if ( pCondFormList && rHint.GetAddress() != BCA_BRDCST_ALWAYS )
+ pCondFormList->SourceChanged( rHint.GetAddress() );
+}
+
+
+void ScDocument::AreaBroadcast( const ScHint& rHint )
+{
+ if ( !pBASM )
+ return ; // Clipboard or Undo
+ if ( !nHardRecalcState )
+ {
+ ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
+ if ( pBASM->AreaBroadcast( rHint ) )
+ TrackFormulas( rHint.GetId() );
+ }
+
+ // Repaint fuer bedingte Formate mit relativen Referenzen:
+ if ( pCondFormList && rHint.GetAddress() != BCA_BRDCST_ALWAYS )
+ pCondFormList->SourceChanged( rHint.GetAddress() );
+}
+
+
+void ScDocument::AreaBroadcastInRange( const ScRange& rRange, const ScHint& rHint )
+{
+ if ( !pBASM )
+ return ; // Clipboard or Undo
+ if ( !nHardRecalcState )
+ {
+ ScBulkBroadcast aBulkBroadcast( pBASM); // scoped bulk broadcast
+ if ( pBASM->AreaBroadcastInRange( rRange, rHint ) )
+ TrackFormulas( rHint.GetId() );
+ }
+
+ // Repaint for conditional formats containing relative references.
+ //! This is _THE_ bottle neck!
+ if ( pCondFormList )
+ {
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ rRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ ScAddress aAddress( rRange.aStart );
+ for ( nTab = nTab1; nTab <= nTab2; ++nTab )
+ {
+ aAddress.SetTab( nTab );
+ for ( nCol = nCol1; nCol <= nCol2; ++nCol )
+ {
+ aAddress.SetCol( nCol );
+ for ( nRow = nRow1; nRow <= nRow2; ++nRow )
+ {
+ aAddress.SetRow( nRow );
+ pCondFormList->SourceChanged( aAddress );
+ }
+ }
+ }
+ }
+}
+
+
+void ScDocument::DelBroadcastAreasInRange( const ScRange& rRange )
+{
+ if ( pBASM )
+ pBASM->DelBroadcastAreasInRange( rRange );
+}
+
+void ScDocument::StartListeningCell( const ScAddress& rAddress,
+ SvtListener* pListener )
+{
+ DBG_ASSERT(pListener, "StartListeningCell: pListener Null");
+ SCTAB nTab = rAddress.Tab();
+ if (pTab[nTab])
+ pTab[nTab]->StartListening( rAddress, pListener );
+}
+
+void ScDocument::EndListeningCell( const ScAddress& rAddress,
+ SvtListener* pListener )
+{
+ DBG_ASSERT(pListener, "EndListeningCell: pListener Null");
+ SCTAB nTab = rAddress.Tab();
+ if (pTab[nTab])
+ pTab[nTab]->EndListening( rAddress, pListener );
+}
+
+
+void ScDocument::PutInFormulaTree( ScFormulaCell* pCell )
+{
+ DBG_ASSERT( pCell, "PutInFormulaTree: pCell Null" );
+ RemoveFromFormulaTree( pCell );
+ // anhaengen
+ if ( pEOFormulaTree )
+ pEOFormulaTree->SetNext( pCell );
+ else
+ pFormulaTree = pCell; // kein Ende, kein Anfang..
+ pCell->SetPrevious( pEOFormulaTree );
+ pCell->SetNext( 0 );
+ pEOFormulaTree = pCell;
+ nFormulaCodeInTree += pCell->GetCode()->GetCodeLen();
+}
+
+
+void ScDocument::RemoveFromFormulaTree( ScFormulaCell* pCell )
+{
+ DBG_ASSERT( pCell, "RemoveFromFormulaTree: pCell Null" );
+ ScFormulaCell* pPrev = pCell->GetPrevious();
+ // wenn die Zelle die erste oder sonstwo ist
+ if ( pPrev || pFormulaTree == pCell )
+ {
+ ScFormulaCell* pNext = pCell->GetNext();
+ if ( pPrev )
+ pPrev->SetNext( pNext ); // gibt Vorlaeufer
+ else
+ pFormulaTree = pNext; // ist erste Zelle
+ if ( pNext )
+ pNext->SetPrevious( pPrev ); // gibt Nachfolger
+ else
+ pEOFormulaTree = pPrev; // ist letzte Zelle
+ pCell->SetPrevious( 0 );
+ pCell->SetNext( 0 );
+ USHORT nRPN = pCell->GetCode()->GetCodeLen();
+ if ( nFormulaCodeInTree >= nRPN )
+ nFormulaCodeInTree -= nRPN;
+ else
+ {
+ DBG_ERRORFILE( "RemoveFromFormulaTree: nFormulaCodeInTree < nRPN" );
+ nFormulaCodeInTree = 0;
+ }
+ }
+ else if ( !pFormulaTree && nFormulaCodeInTree )
+ {
+ DBG_ERRORFILE( "!pFormulaTree && nFormulaCodeInTree != 0" );
+ nFormulaCodeInTree = 0;
+ }
+}
+
+
+BOOL ScDocument::IsInFormulaTree( ScFormulaCell* pCell ) const
+{
+ return pCell->GetPrevious() || pFormulaTree == pCell;
+}
+
+
+void ScDocument::CalcFormulaTree( BOOL bOnlyForced, BOOL bNoProgress )
+{
+ DBG_ASSERT( !IsCalculatingFormulaTree(), "CalcFormulaTree recursion" );
+ // never ever recurse into this, might end up lost in infinity
+ if ( IsCalculatingFormulaTree() )
+ return ;
+ bCalculatingFormulaTree = TRUE;
+
+ SetForcedFormulaPending( FALSE );
+ BOOL bOldIdleDisabled = IsIdleDisabled();
+ DisableIdle( TRUE );
+ BOOL bOldAutoCalc = GetAutoCalc();
+ //! _nicht_ SetAutoCalc( TRUE ) weil das evtl. CalcFormulaTree( TRUE )
+ //! aufruft, wenn vorher disabled war und bHasForcedFormulas gesetzt ist
+ bAutoCalc = TRUE;
+ if ( nHardRecalcState )
+ CalcAll();
+ else
+ {
+ ScFormulaCell* pCell = pFormulaTree;
+ while ( pCell )
+ {
+ if ( pCell->GetDirty() )
+ pCell = pCell->GetNext(); // alles klar
+ else
+ {
+ if ( pCell->GetCode()->IsRecalcModeAlways() )
+ {
+ // pCell wird im SetDirty neu angehaengt!
+ ScFormulaCell* pNext = pCell->GetNext();
+ pCell->SetDirty();
+ // falls pNext==0 und neue abhaengige hinten angehaengt
+ // wurden, so macht das nichts, da die alle bDirty sind
+ pCell = pNext;
+ }
+ else
+ { // andere simpel berechnen
+ pCell->SetDirtyVar();
+ pCell = pCell->GetNext();
+ }
+ }
+ }
+ BOOL bProgress = !bOnlyForced && nFormulaCodeInTree && !bNoProgress;
+ if ( bProgress )
+ ScProgress::CreateInterpretProgress( this, TRUE );
+
+ pCell = pFormulaTree;
+ ScFormulaCell* pLastNoGood = 0;
+ while ( pCell )
+ {
+ // Interpret setzt bDirty zurueck und callt Remove, auch der referierten!
+ // bei RECALCMODE_ALWAYS bleibt die Zelle
+ if ( bOnlyForced )
+ {
+ if ( pCell->GetCode()->IsRecalcModeForced() )
+ pCell->Interpret();
+ }
+ else
+ {
+ pCell->Interpret();
+ }
+ if ( pCell->GetPrevious() || pCell == pFormulaTree )
+ { // (IsInFormulaTree(pCell)) kein Remove gewesen => next
+ pLastNoGood = pCell;
+ pCell = pCell->GetNext();
+ }
+ else
+ {
+ if ( pFormulaTree )
+ {
+ if ( pFormulaTree->GetDirty() && !bOnlyForced )
+ {
+ pCell = pFormulaTree;
+ pLastNoGood = 0;
+ }
+ else
+ {
+ // IsInFormulaTree(pLastNoGood)
+ if ( pLastNoGood && (pLastNoGood->GetPrevious() ||
+ pLastNoGood == pFormulaTree) )
+ pCell = pLastNoGood->GetNext();
+ else
+ {
+ pCell = pFormulaTree;
+ while ( pCell && !pCell->GetDirty() )
+ pCell = pCell->GetNext();
+ if ( pCell )
+ pLastNoGood = pCell->GetPrevious();
+ }
+ }
+ }
+ else
+ pCell = 0;
+ }
+ if ( ScProgress::IsUserBreak() )
+ pCell = 0;
+ }
+ if ( bProgress )
+ ScProgress::DeleteInterpretProgress();
+ }
+ bAutoCalc = bOldAutoCalc;
+ DisableIdle( bOldIdleDisabled );
+ bCalculatingFormulaTree = FALSE;
+}
+
+
+void ScDocument::ClearFormulaTree()
+{
+ ScFormulaCell* pCell;
+ ScFormulaCell* pTree = pFormulaTree;
+ while ( pTree )
+ {
+ pCell = pTree;
+ pTree = pCell->GetNext();
+ if ( !pCell->GetCode()->IsRecalcModeAlways() )
+ RemoveFromFormulaTree( pCell );
+ }
+}
+
+
+void ScDocument::AppendToFormulaTrack( ScFormulaCell* pCell )
+{
+ DBG_ASSERT( pCell, "AppendToFormulaTrack: pCell Null" );
+ // Zelle kann nicht in beiden Listen gleichzeitig sein
+ RemoveFromFormulaTrack( pCell );
+ RemoveFromFormulaTree( pCell );
+ if ( pEOFormulaTrack )
+ pEOFormulaTrack->SetNextTrack( pCell );
+ else
+ pFormulaTrack = pCell; // kein Ende, kein Anfang..
+ pCell->SetPreviousTrack( pEOFormulaTrack );
+ pCell->SetNextTrack( 0 );
+ pEOFormulaTrack = pCell;
+ ++nFormulaTrackCount;
+}
+
+
+void ScDocument::RemoveFromFormulaTrack( ScFormulaCell* pCell )
+{
+ DBG_ASSERT( pCell, "RemoveFromFormulaTrack: pCell Null" );
+ ScFormulaCell* pPrev = pCell->GetPreviousTrack();
+ // wenn die Zelle die erste oder sonstwo ist
+ if ( pPrev || pFormulaTrack == pCell )
+ {
+ ScFormulaCell* pNext = pCell->GetNextTrack();
+ if ( pPrev )
+ pPrev->SetNextTrack( pNext ); // gibt Vorlaeufer
+ else
+ pFormulaTrack = pNext; // ist erste Zelle
+ if ( pNext )
+ pNext->SetPreviousTrack( pPrev ); // gibt Nachfolger
+ else
+ pEOFormulaTrack = pPrev; // ist letzte Zelle
+ pCell->SetPreviousTrack( 0 );
+ pCell->SetNextTrack( 0 );
+ --nFormulaTrackCount;
+ }
+}
+
+
+BOOL ScDocument::IsInFormulaTrack( ScFormulaCell* pCell ) const
+{
+ return pCell->GetPreviousTrack() || pFormulaTrack == pCell;
+}
+
+
+/*
+ Der erste wird gebroadcastet,
+ die dadurch entstehenden werden durch das Notify an den Track gehaengt.
+ Der nachfolgende broadcastet wieder usw.
+ View stoesst Interpret an.
+ */
+void ScDocument::TrackFormulas( ULONG nHintId )
+{
+
+ if ( pFormulaTrack )
+ {
+ erBEEPER();
+ SvtBroadcaster* pBC;
+ ScFormulaCell* pTrack;
+ ScFormulaCell* pNext;
+ pTrack = pFormulaTrack;
+ do
+ {
+ ScHint aHint( nHintId, pTrack->aPos, pTrack );
+ if ( ( pBC = pTrack->GetBroadcaster() ) != NULL )
+ pBC->Broadcast( aHint );
+ pBASM->AreaBroadcast( aHint );
+ // Repaint fuer bedingte Formate mit relativen Referenzen:
+ if ( pCondFormList )
+ pCondFormList->SourceChanged( pTrack->aPos );
+ pTrack = pTrack->GetNextTrack();
+ } while ( pTrack );
+ pTrack = pFormulaTrack;
+ BOOL bHaveForced = FALSE;
+ do
+ {
+ pNext = pTrack->GetNextTrack();
+ RemoveFromFormulaTrack( pTrack );
+ PutInFormulaTree( pTrack );
+ if ( pTrack->GetCode()->IsRecalcModeForced() )
+ bHaveForced = TRUE;
+ pTrack = pNext;
+ } while ( pTrack );
+ if ( bHaveForced )
+ {
+ SetForcedFormulas( TRUE );
+ if ( bAutoCalc && !IsAutoCalcShellDisabled() && !IsInInterpreter()
+ && !IsCalculatingFormulaTree() )
+ CalcFormulaTree( TRUE );
+ else
+ SetForcedFormulaPending( TRUE );
+ }
+ }
+ DBG_ASSERT( nFormulaTrackCount==0, "TrackFormulas: nFormulaTrackCount!=0" );
+}
+
+
+void ScDocument::StartAllListeners()
+{
+ for ( SCTAB i = 0; i <= MAXTAB; ++i )
+ if ( pTab[i] )
+ pTab[i]->StartAllListeners();
+}
+
+void ScDocument::UpdateBroadcastAreas( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz
+ )
+{
+ BOOL bExpandRefsOld = IsExpandRefs();
+ if ( eUpdateRefMode == URM_INSDEL && (nDx > 0 || nDy > 0 || nDz > 0) )
+ SetExpandRefs( SC_MOD()->GetInputOptions().GetExpandRefs() );
+ if ( pBASM )
+ pBASM->UpdateBroadcastAreas( eUpdateRefMode, rRange, nDx, nDy, nDz );
+ SetExpandRefs( bExpandRefsOld );
+}
+
+void ScDocument::SetAutoCalc( BOOL bNewAutoCalc )
+{
+ BOOL bOld = bAutoCalc;
+ bAutoCalc = bNewAutoCalc;
+ if ( !bOld && bNewAutoCalc && bHasForcedFormulas )
+ {
+ if ( IsAutoCalcShellDisabled() )
+ SetForcedFormulaPending( TRUE );
+ else if ( !IsInInterpreter() )
+ CalcFormulaTree( TRUE );
+ }
+}
+
+
+
diff --git a/sc/source/core/data/documen8.cxx b/sc/source/core/data/documen8.cxx
new file mode 100644
index 000000000000..0d12c82dec87
--- /dev/null
+++ b/sc/source/core/data/documen8.cxx
@@ -0,0 +1,1623 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: documen8.cxx,v $
+ * $Revision: 1.52.32.3 $
+ *
+ * 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"
+
+
+#define _ZFORLIST_DECLARE_TABLE
+#include "scitems.hxx"
+#include <svx/eeitem.hxx>
+
+#include <tools/string.hxx>
+#include <svx/editobj.hxx>
+#include <svx/editstat.hxx>
+#include <svx/frmdiritem.hxx>
+#include <svx/langitem.hxx>
+#include <svx/linkmgr.hxx>
+#include <svx/scripttypeitem.hxx>
+#include <svx/unolingu.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svtools/flagitem.hxx>
+#include <svtools/intitem.hxx>
+#define _SVSTDARR_USHORTS
+#include <svtools/svstdarr.hxx>
+#include <svtools/zforlist.hxx>
+#include <svtools/zformat.hxx>
+#include <svtools/misccfg.hxx>
+#include <sfx2/app.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <svtools/securityoptions.hxx>
+
+#include <vcl/virdev.hxx>
+#include <vcl/msgbox.hxx>
+
+#include "inputopt.hxx"
+#include "global.hxx"
+#include "table.hxx"
+#include "column.hxx"
+#include "cell.hxx"
+#include "poolhelp.hxx"
+#include "docpool.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "docoptio.hxx"
+#include "viewopti.hxx"
+#include "scextopt.hxx"
+#include "rechead.hxx"
+#include "ddelink.hxx"
+#include "scmatrix.hxx"
+#include "arealink.hxx"
+#include "dociter.hxx"
+#include "patattr.hxx"
+#include "hints.hxx"
+#include "editutil.hxx"
+#include "progress.hxx"
+#include "document.hxx"
+#include "chartlis.hxx"
+#include "chartlock.hxx"
+#include "refupdat.hxx"
+#include "validat.hxx" // fuer HasMacroCalls
+#include "markdata.hxx"
+#include "scmod.hxx"
+#include "printopt.hxx"
+#include "externalrefmgr.hxx"
+#include "globstr.hrc"
+#include "sc.hrc"
+#include "charthelper.hxx"
+
+#define GET_SCALEVALUE(set,id) ((const SfxUInt16Item&)(set.Get( id ))).GetValue()
+
+// states for online spelling in the visible range (0 is set initially)
+#define VSPL_START 0
+#define VSPL_DONE 1
+
+
+// STATIC DATA -----------------------------------------------------------
+
+//------------------------------------------------------------------------
+
+void ScDocument::ImplCreateOptions()
+{
+ pDocOptions = new ScDocOptions();
+ pViewOptions = new ScViewOptions();
+}
+
+//------------------------------------------------------------------------
+
+void ScDocument::ImplDeleteOptions()
+{
+ delete pDocOptions;
+ delete pViewOptions;
+ delete pExtDocOptions;
+}
+
+//------------------------------------------------------------------------
+
+SfxPrinter* ScDocument::GetPrinter(BOOL bCreateIfNotExist)
+{
+ if ( !pPrinter && bCreateIfNotExist )
+ {
+ SfxItemSet* pSet =
+ new SfxItemSet( *xPoolHelper->GetDocPool(),
+ SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
+ SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC,
+ SID_PRINT_SELECTEDSHEET, SID_PRINT_SELECTEDSHEET,
+ SID_SCPRINTOPTIONS, SID_SCPRINTOPTIONS,
+ NULL );
+
+ SfxMiscCfg* pOffCfg = SFX_APP()->GetMiscConfig();
+ if ( pOffCfg )
+ {
+ USHORT nFlags = 0;
+ if ( pOffCfg->IsPaperOrientationWarning() )
+ nFlags |= SFX_PRINTER_CHG_ORIENTATION;
+ if ( pOffCfg->IsPaperSizeWarning() )
+ nFlags |= SFX_PRINTER_CHG_SIZE;
+ pSet->Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, nFlags ) );
+ pSet->Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, pOffCfg->IsNotFoundWarning() ) );
+ }
+
+ pPrinter = new SfxPrinter( pSet );
+ pPrinter->SetMapMode( MAP_100TH_MM );
+ UpdateDrawPrinter();
+ pPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
+ }
+
+ return pPrinter;
+}
+
+//------------------------------------------------------------------------
+
+void ScDocument::SetPrinter( SfxPrinter* pNewPrinter )
+{
+ if ( pNewPrinter == pPrinter )
+ {
+ // #i6706# SetPrinter is called with the same printer again if
+ // the JobSetup has changed. In that case just call UpdateDrawPrinter
+ // (SetRefDevice for drawing layer) because of changed text sizes.
+ UpdateDrawPrinter();
+ }
+ else
+ {
+ SfxPrinter* pOld = pPrinter;
+ pPrinter = pNewPrinter;
+ UpdateDrawPrinter();
+ pPrinter->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
+ delete pOld;
+ }
+ InvalidateTextWidth(NULL, NULL, FALSE); // in both cases
+}
+
+//------------------------------------------------------------------------
+
+void ScDocument::SetPrintOptions()
+{
+ if ( !pPrinter ) GetPrinter(); // setzt pPrinter
+ DBG_ASSERT( pPrinter, "Error in printer creation :-/" );
+
+ if ( pPrinter )
+ {
+ SfxMiscCfg* pOffCfg = SFX_APP()->GetMiscConfig();
+ if ( pOffCfg )
+ {
+ SfxItemSet aOptSet( pPrinter->GetOptions() );
+
+ USHORT nFlags = 0;
+ if ( pOffCfg->IsPaperOrientationWarning() )
+ nFlags |= SFX_PRINTER_CHG_ORIENTATION;
+ if ( pOffCfg->IsPaperSizeWarning() )
+ nFlags |= SFX_PRINTER_CHG_SIZE;
+ aOptSet.Put( SfxFlagItem( SID_PRINTER_CHANGESTODOC, nFlags ) );
+ aOptSet.Put( SfxBoolItem( SID_PRINTER_NOTFOUND_WARN, pOffCfg->IsNotFoundWarning() ) );
+
+ pPrinter->SetOptions( aOptSet );
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+
+VirtualDevice* ScDocument::GetVirtualDevice_100th_mm()
+{
+ if (!pVirtualDevice_100th_mm)
+ {
+// pVirtualDevice_100th_mm = new VirtualDevice;
+// pVirtualDevice_100th_mm->SetMapMode( MAP_100TH_MM );
+
+ pVirtualDevice_100th_mm = new VirtualDevice( 1 );
+ pVirtualDevice_100th_mm->SetReferenceDevice(VirtualDevice::REFDEV_MODE_MSO1);
+ MapMode aMapMode( pVirtualDevice_100th_mm->GetMapMode() );
+ aMapMode.SetMapUnit( MAP_100TH_MM );
+ pVirtualDevice_100th_mm->SetMapMode( aMapMode );
+ }
+ return pVirtualDevice_100th_mm;
+}
+
+OutputDevice* ScDocument::GetRefDevice()
+{
+ // Create printer like ref device, see Writer...
+ OutputDevice* pRefDevice = NULL;
+ if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
+ pRefDevice = GetPrinter();
+ else
+ pRefDevice = GetVirtualDevice_100th_mm();
+ return pRefDevice;
+}
+
+//------------------------------------------------------------------------
+
+void ScDocument::ModifyStyleSheet( SfxStyleSheetBase& rStyleSheet,
+ const SfxItemSet& rChanges )
+{
+ SfxItemSet& rSet = rStyleSheet.GetItemSet();
+
+ switch ( rStyleSheet.GetFamily() )
+ {
+ case SFX_STYLE_FAMILY_PAGE:
+ {
+ const USHORT nOldScale = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALE);
+ const USHORT nOldScaleToPages = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALETOPAGES);
+ rSet.Put( rChanges );
+ const USHORT nNewScale = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALE);
+ const USHORT nNewScaleToPages = GET_SCALEVALUE(rSet,ATTR_PAGE_SCALETOPAGES);
+
+ if ( (nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages) )
+ InvalidateTextWidth( rStyleSheet.GetName() );
+
+ if( SvtLanguageOptions().IsCTLFontEnabled() )
+ {
+ const SfxPoolItem *pItem = NULL;
+ if( rChanges.GetItemState(ATTR_WRITINGDIR, TRUE, &pItem ) == SFX_ITEM_SET )
+ ScChartHelper::DoUpdateAllCharts( this );
+ }
+ }
+ break;
+
+ case SFX_STYLE_FAMILY_PARA:
+ {
+ BOOL bNumFormatChanged;
+ if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
+ rSet, rChanges ) )
+ InvalidateTextWidth( NULL, NULL, bNumFormatChanged );
+ ULONG nOldFormat =
+ ((const SfxUInt32Item*)&rSet.Get(
+ ATTR_VALUE_FORMAT ))->GetValue();
+ ULONG nNewFormat =
+ ((const SfxUInt32Item*)&rChanges.Get(
+ ATTR_VALUE_FORMAT ))->GetValue();
+ LanguageType eNewLang, eOldLang;
+ eNewLang = eOldLang = LANGUAGE_DONTKNOW;
+ if ( nNewFormat != nOldFormat )
+ {
+ SvNumberFormatter* pFormatter = GetFormatTable();
+ eOldLang = pFormatter->GetEntry( nOldFormat )->GetLanguage();
+ eNewLang = pFormatter->GetEntry( nNewFormat )->GetLanguage();
+ }
+
+ // Bedeutung der Items in rChanges:
+ // Item gesetzt - Aenderung uebernehmen
+ // Dontcare - Default setzen
+ // Default - keine Aenderung
+ // ("keine Aenderung" geht nicht mit PutExtended, darum Schleife)
+ for (USHORT nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++)
+ {
+ const SfxPoolItem* pItem;
+ SfxItemState eState = rChanges.GetItemState( nWhich, FALSE, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ rSet.Put( *pItem );
+ else if ( eState == SFX_ITEM_DONTCARE )
+ rSet.ClearItem( nWhich );
+ // bei Default nichts
+ }
+
+ if ( eNewLang != eOldLang )
+ rSet.Put(
+ SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+
+void ScDocument::CopyStdStylesFrom( ScDocument* pSrcDoc )
+{
+ // #b5017505# number format exchange list has to be handled here, too
+
+ SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
+ SvNumberFormatter* pOtherFormatter = pSrcDoc->xPoolHelper->GetFormTable();
+ if (pOtherFormatter && pOtherFormatter != pThisFormatter)
+ {
+ SvNumberFormatterIndexTable* pExchangeList =
+ pThisFormatter->MergeFormatter(*(pOtherFormatter));
+ if (pExchangeList->Count() > 0)
+ pFormatExchangeList = pExchangeList;
+ }
+
+ xPoolHelper->GetStylePool()->CopyStdStylesFrom( pSrcDoc->xPoolHelper->GetStylePool() );
+
+ pFormatExchangeList = NULL;
+}
+
+//------------------------------------------------------------------------
+
+void ScDocument::InvalidateTextWidth( const String& rStyleName )
+{
+ const SCTAB nCount = GetTableCount();
+ for ( SCTAB i=0; i<nCount && pTab[i]; i++ )
+ if ( pTab[i]->GetPageStyle() == rStyleName )
+ InvalidateTextWidth( i );
+}
+
+//------------------------------------------------------------------------
+
+void ScDocument::InvalidateTextWidth( SCTAB nTab )
+{
+ ScAddress aAdrFrom( 0, 0, nTab );
+ ScAddress aAdrTo ( MAXCOL, MAXROW, nTab );
+ InvalidateTextWidth( &aAdrFrom, &aAdrTo, FALSE );
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScDocument::IsPageStyleInUse( const String& rStrPageStyle, SCTAB* pInTab )
+{
+ BOOL bInUse = FALSE;
+ const SCTAB nCount = GetTableCount();
+ SCTAB i;
+
+ for ( i = 0; !bInUse && i < nCount && pTab[i]; i++ )
+ bInUse = ( pTab[i]->GetPageStyle() == rStrPageStyle );
+
+ if ( pInTab )
+ *pInTab = i-1;
+
+ return bInUse;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScDocument::RemovePageStyleInUse( const String& rStyle )
+{
+ BOOL bWasInUse = FALSE;
+ const SCTAB nCount = GetTableCount();
+
+ for ( SCTAB i=0; i<nCount && pTab[i]; i++ )
+ if ( pTab[i]->GetPageStyle() == rStyle )
+ {
+ bWasInUse = TRUE;
+ pTab[i]->SetPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
+ }
+
+ return bWasInUse;
+}
+
+BOOL ScDocument::RenamePageStyleInUse( const String& rOld, const String& rNew )
+{
+ BOOL bWasInUse = FALSE;
+ const SCTAB nCount = GetTableCount();
+
+ for ( SCTAB i=0; i<nCount && pTab[i]; i++ )
+ if ( pTab[i]->GetPageStyle() == rOld )
+ {
+ bWasInUse = TRUE;
+ pTab[i]->SetPageStyle( rNew );
+ }
+
+ return bWasInUse;
+}
+
+//------------------------------------------------------------------------
+
+BYTE ScDocument::GetEditTextDirection(SCTAB nTab) const
+{
+ EEHorizontalTextDirection eRet = EE_HTEXTDIR_DEFAULT;
+
+ String aStyleName = GetPageStyle( nTab );
+ SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aStyleName, SFX_STYLE_FAMILY_PAGE );
+ if ( pStyle )
+ {
+ SfxItemSet& rStyleSet = pStyle->GetItemSet();
+ SvxFrameDirection eDirection = (SvxFrameDirection)
+ ((const SvxFrameDirectionItem&)rStyleSet.Get( ATTR_WRITINGDIR )).GetValue();
+
+ if ( eDirection == FRMDIR_HORI_LEFT_TOP )
+ eRet = EE_HTEXTDIR_L2R;
+ else if ( eDirection == FRMDIR_HORI_RIGHT_TOP )
+ eRet = EE_HTEXTDIR_R2L;
+ // else (invalid for EditEngine): keep "default"
+ }
+
+ return sal::static_int_cast<BYTE>(eRet);
+}
+
+//------------------------------------------------------------------------
+
+void ScDocument::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
+ BOOL bNumFormatChanged )
+{
+ BOOL bBroadcast = (bNumFormatChanged && GetDocOptions().IsCalcAsShown() && !IsImportingXML() && !IsClipboard());
+ if ( pAdrFrom && !pAdrTo )
+ {
+ const SCTAB nTab = pAdrFrom->Tab();
+
+ if ( pTab[nTab] )
+ pTab[nTab]->InvalidateTextWidth( pAdrFrom, NULL, bNumFormatChanged, bBroadcast );
+ }
+ else
+ {
+ const SCTAB nTabStart = pAdrFrom ? pAdrFrom->Tab() : 0;
+ const SCTAB nTabEnd = pAdrTo ? pAdrTo->Tab() : MAXTAB;
+
+ for ( SCTAB nTab=nTabStart; nTab<=nTabEnd; nTab++ )
+ if ( pTab[nTab] )
+ pTab[nTab]->InvalidateTextWidth( pAdrFrom, pAdrTo, bNumFormatChanged, bBroadcast );
+ }
+}
+
+//------------------------------------------------------------------------
+
+#define CALCMAX 1000 // Berechnungen
+#define ABORT_EVENTS (INPUT_ANY & ~INPUT_TIMER & ~INPUT_OTHER)
+
+BOOL ScDocument::IdleCalcTextWidth() // TRUE = demnaechst wieder versuchen
+{
+ // #i75610# if a printer hasn't been set or created yet, don't create one for this
+ if ( bIdleDisabled || IsInLinkUpdate() || GetPrinter(FALSE) == NULL )
+ return FALSE;
+ bIdleDisabled = TRUE;
+
+// ULONG nMs = 0;
+// USHORT nIter = 0;
+
+ const ULONG nStart = Time::GetSystemTicks();
+ double nPPTX = 0.0;
+ double nPPTY = 0.0;
+ OutputDevice* pDev = NULL;
+ MapMode aOldMap;
+ ScStyleSheet* pStyle = NULL;
+ ScColumnIterator* pColIter = NULL;
+ ScTable* pTable = NULL;
+ ScColumn* pColumn = NULL;
+ ScBaseCell* pCell = NULL;
+ SCTAB nTab = aCurTextWidthCalcPos.Tab();
+ SCROW nRow = aCurTextWidthCalcPos.Row();
+ SCsCOL nCol = aCurTextWidthCalcPos.Col();
+ USHORT nRestart = 0;
+ USHORT nZoom = 0;
+ BOOL bNeedMore= FALSE;
+
+ if ( !ValidRow(nRow) )
+ nRow = 0, nCol--;
+ if ( nCol < 0 )
+ nCol = MAXCOL, nTab++;
+ if ( !ValidTab(nTab) || !pTab[nTab] )
+ nTab = 0;
+
+// DBG_ERROR( String("Start = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) );
+
+ // SearchMask/Family muss gemerkt werden,
+ // damit z.B. der Organizer nicht durcheinanderkommt, wenn zwischendurch eine
+ // Query-Box aufgemacht wird !!!
+
+ ScStyleSheetPool* pStylePool = xPoolHelper->GetStylePool();
+ USHORT nOldMask = pStylePool->GetSearchMask();
+ SfxStyleFamily eOldFam = pStylePool->GetSearchFamily();
+
+ pTable = pTab[nTab];
+ pStylePool->SetSearchMask( SFX_STYLE_FAMILY_PAGE, SFXSTYLEBIT_ALL );
+ pStyle = (ScStyleSheet*)pStylePool->Find( pTable->aPageStyle,
+ SFX_STYLE_FAMILY_PAGE );
+
+ DBG_ASSERT( pStyle, "Missing StyleSheet :-/" );
+
+ BOOL bProgress = FALSE;
+ if ( pStyle && 0 == GET_SCALEVALUE(pStyle->GetItemSet(),ATTR_PAGE_SCALETOPAGES) )
+ {
+ USHORT nCount = 0;
+
+ nZoom = GET_SCALEVALUE(pStyle->GetItemSet(),ATTR_PAGE_SCALE);
+ Fraction aZoomFract( nZoom, 100 );
+ pColumn = &pTable->aCol[nCol];
+ pColIter = new ScColumnIterator( pColumn, nRow, MAXROW );
+
+ while ( (nZoom > 0) && (nCount < CALCMAX) && (nRestart < 2) )
+ {
+ if ( pColIter->Next( nRow, pCell ) )
+ {
+ if ( TEXTWIDTH_DIRTY == pCell->GetTextWidth() )
+ {
+ if ( !pDev )
+ {
+ pDev = GetPrinter();
+ aOldMap = pDev->GetMapMode();
+ pDev->SetMapMode( MAP_PIXEL ); // wichtig fuer GetNeededSize
+
+ Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP );
+ nPPTX = aPix1000.X() / 1000.0;
+ nPPTY = aPix1000.Y() / 1000.0;
+ }
+ if ( !bProgress && pCell->GetCellType() == CELLTYPE_FORMULA
+ && ((ScFormulaCell*)pCell)->GetDirty() )
+ {
+ ScProgress::CreateInterpretProgress( this, FALSE );
+ bProgress = TRUE;
+ }
+
+// DBG_ERROR( String("t,c,r = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) );
+// DBG_ERROR( String("nOldWidth = ") + String(pCell->GetTextWidth()) );
+
+ USHORT nNewWidth = (USHORT)GetNeededSize( nCol, nRow, nTab,
+ pDev, nPPTX, nPPTY,
+ aZoomFract,aZoomFract, TRUE,
+ TRUE ); // bTotalSize
+
+// DBG_ERROR( String("nNewWidth = ") + String(nNewWidth) );
+
+ pCell->SetTextWidth( nNewWidth );
+
+ bNeedMore = TRUE;
+ }
+ }
+ else
+ {
+ BOOL bNewTab = FALSE;
+
+ nRow = 0;
+ nCol--;
+
+ if ( nCol < 0 )
+ {
+ nCol = MAXCOL;
+ nTab++;
+ bNewTab = TRUE;
+ }
+
+ if ( !ValidTab(nTab) || !pTab[nTab] )
+ {
+ nTab = 0;
+ nRestart++;
+ bNewTab = TRUE;
+ }
+
+ if ( nRestart < 2 )
+ {
+ if ( bNewTab )
+ {
+ pTable = pTab[nTab];
+ pStyle = (ScStyleSheet*)pStylePool->Find( pTable->aPageStyle,
+ SFX_STYLE_FAMILY_PAGE );
+
+ if ( pStyle )
+ {
+ SfxItemSet& rSet = pStyle->GetItemSet();
+ if ( GET_SCALEVALUE( rSet, ATTR_PAGE_SCALETOPAGES ) == 0 )
+ nZoom = GET_SCALEVALUE(rSet, ATTR_PAGE_SCALE );
+ else
+ nZoom = 0;
+ }
+ else
+ {
+ DBG_ERROR( "Missing StyleSheet :-/" );
+ }
+ }
+
+ if ( nZoom > 0 )
+ {
+ delete pColIter;
+
+ pColumn = &pTable->aCol[nCol];
+ pColIter = new ScColumnIterator( pColumn, nRow, MAXROW );
+ }
+ else
+ nTab++; // Tabelle nicht mit absolutem Zoom -> naechste
+ }
+ }
+
+// nIter = nCount;
+
+ nCount++;
+
+ // Idle Berechnung abbrechen, wenn Berechnungen laenger als
+ // 50ms dauern, oder nach 32 Berechnungen mal nachschauen, ob
+ // bestimmte Events anstehen, die Beachtung wuenschen:
+
+// nMs = SysTicksToMs( GetSysTicks() - nStart );
+
+ if ( ( 50L < Time::GetSystemTicks() - nStart )
+ || ( !(nCount&31) && Application::AnyInput( ABORT_EVENTS ) ) )
+ nCount = CALCMAX;
+ }
+ }
+ else
+ nTab++; // Tabelle nicht mit absolutem Zoom -> naechste
+
+ if ( bProgress )
+ ScProgress::DeleteInterpretProgress();
+
+ delete pColIter;
+
+// DBG_ERROR( String(nCount) + String(" End = ") + String(nTab) + String(',') + String(nCol) + String(',') + String(nRow) );
+
+ if (pDev)
+ pDev->SetMapMode(aOldMap);
+
+ aCurTextWidthCalcPos.SetTab( nTab );
+ aCurTextWidthCalcPos.SetRow( nRow );
+ aCurTextWidthCalcPos.SetCol( (SCCOL)nCol );
+
+// DBG_ERROR( String(nMs) + String(" ms (") + String(nIter) + String(')') );
+
+ pStylePool->SetSearchMask( eOldFam, nOldMask );
+ bIdleDisabled = FALSE;
+
+ return bNeedMore;
+}
+
+//------------------------------------------------------------------------
+
+class ScSpellStatus
+{
+public:
+ BOOL bModified;
+
+ ScSpellStatus() : bModified(FALSE) {};
+
+ DECL_LINK (EventHdl, EditStatus*);
+};
+
+IMPL_LINK( ScSpellStatus, EventHdl, EditStatus *, pStatus )
+{
+ ULONG nStatus = pStatus->GetStatusWord();
+ if ( nStatus & EE_STAT_WRONGWORDCHANGED )
+ bModified = TRUE;
+
+ return 0;
+}
+
+// SPELL_MAXCELLS muss mindestens 256 sein, solange am Iterator keine
+// Start-Spalte gesetzt werden kann
+
+//! SPELL_MAXTEST fuer Timer und Idle unterschiedlich ???
+
+// SPELL_MAXTEST now divided between visible and rest of document
+
+#define SPELL_MAXTEST_VIS 1
+#define SPELL_MAXTEST_ALL 3
+#define SPELL_MAXCELLS 256
+
+BOOL ScDocument::OnlineSpellInRange( const ScRange& rSpellRange, ScAddress& rSpellPos,
+ USHORT nMaxTest )
+{
+ ScEditEngineDefaulter* pEngine = NULL; //! am Dokument speichern
+ SfxItemSet* pDefaults = NULL;
+ ScSpellStatus aStatus;
+
+ USHORT nCellCount = 0; // Zellen insgesamt
+ USHORT nTestCount = 0; // Aufrufe Spelling
+ BOOL bChanged = FALSE; // Aenderungen?
+
+ SCCOL nCol = rSpellRange.aStart.Col(); // iterator always starts on the left edge
+ SCROW nRow = rSpellPos.Row();
+ SCTAB nTab = rSpellPos.Tab();
+ if ( !pTab[nTab] ) // sheet deleted?
+ {
+ nTab = rSpellRange.aStart.Tab();
+ nRow = rSpellRange.aStart.Row();
+ if ( !pTab[nTab] )
+ {
+ // may happen for visible range
+ return FALSE;
+ }
+ }
+ ScHorizontalCellIterator aIter( this, nTab,
+ rSpellRange.aStart.Col(), nRow,
+ rSpellRange.aEnd.Col(), rSpellRange.aEnd.Row() );
+ ScBaseCell* pCell = aIter.GetNext( nCol, nRow );
+ // skip everything left of rSpellPos:
+ while ( pCell && nRow == rSpellPos.Row() && nCol < rSpellPos.Col() )
+ pCell = aIter.GetNext( nCol, nRow );
+ while ( pCell )
+ {
+ CellType eType = pCell->GetCellType();
+ if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
+ {
+ if (!pEngine)
+ {
+ // #71154# ScTabEditEngine is needed
+ // because MapMode must be set for some old documents
+ pEngine = new ScTabEditEngine( this );
+ pEngine->SetControlWord( pEngine->GetControlWord() |
+ ( EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS ) );
+ pEngine->SetStatusEventHdl( LINK( &aStatus, ScSpellStatus, EventHdl ) );
+ // Delimiters hier wie in inputhdl.cxx !!!
+ pEngine->SetWordDelimiters(
+ ScEditUtil::ModifyDelimiters( pEngine->GetWordDelimiters() ) );
+ pDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() );
+
+ com::sun::star::uno::Reference<com::sun::star::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
+
+ pEngine->SetSpeller( xXSpellChecker1 );
+ }
+
+ const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
+ pPattern->FillEditItemSet( pDefaults );
+ pEngine->SetDefaults( pDefaults, FALSE ); //! noetig ?
+
+ USHORT nCellLang = ((const SvxLanguageItem&)
+ pPattern->GetItem(ATTR_FONT_LANGUAGE)).GetValue();
+ if ( nCellLang == LANGUAGE_SYSTEM )
+ nCellLang = Application::GetSettings().GetLanguage(); // never use SYSTEM for spelling
+ pEngine->SetDefaultLanguage( nCellLang );
+
+ if ( eType == CELLTYPE_STRING )
+ {
+ String aText;
+ ((ScStringCell*)pCell)->GetString(aText);
+ pEngine->SetText( aText );
+ }
+ else
+ pEngine->SetText( *((ScEditCell*)pCell)->GetData() );
+
+ aStatus.bModified = FALSE;
+ pEngine->CompleteOnlineSpelling();
+ if ( aStatus.bModified ) // Fehler dazu oder weggekommen?
+ {
+ BOOL bNeedEdit = TRUE; // Test auf einfachen Text
+ if ( !pEngine->HasOnlineSpellErrors() )
+ {
+ ScEditAttrTester aTester( pEngine );
+ bNeedEdit = aTester.NeedsObject();
+ }
+
+ if ( bNeedEdit )
+ {
+ EditTextObject* pNewData = pEngine->CreateTextObject();
+ if ( eType == CELLTYPE_EDIT )
+ ((ScEditCell*)pCell)->SetData( pNewData,
+ pEngine->GetEditTextObjectPool() );
+ else
+ PutCell( nCol, nRow, nTab, new ScEditCell( pNewData,
+ this, pEngine->GetEditTextObjectPool() ) );
+ delete pNewData;
+ }
+ else // einfacher String
+ PutCell( nCol, nRow, nTab, new ScStringCell( pEngine->GetText() ) );
+
+ // Paint
+ if (pShell)
+ {
+ // #47751# Seitenvorschau ist davon nicht betroffen
+ // (sollte jedenfalls nicht)
+ ScPaintHint aHint( ScRange( nCol, nRow, nTab ), PAINT_GRID );
+ aHint.SetPrintFlag( FALSE );
+ pShell->Broadcast( aHint );
+ }
+
+ bChanged = TRUE;
+ }
+
+ if ( ++nTestCount >= nMaxTest ) // checked enough text?
+ break;
+ }
+
+ if ( ++nCellCount >= SPELL_MAXCELLS ) // seen enough cells?
+ break;
+
+ pCell = aIter.GetNext( nCol, nRow );
+ }
+
+ if ( pCell )
+ {
+ ++nCol; // continue after last cell
+ if ( nCol > rSpellRange.aEnd.Col() )
+ {
+ nCol = rSpellRange.aStart.Col();
+ ++nRow;
+ if ( nRow > rSpellRange.aEnd.Row() )
+ pCell = NULL;
+ }
+ }
+
+ if (!pCell) // end of range reached -> next sheet
+ {
+ ++nTab;
+ if ( nTab > rSpellRange.aEnd.Tab() || !pTab[nTab] )
+ nTab = rSpellRange.aStart.Tab();
+ nCol = rSpellRange.aStart.Col();
+ nRow = rSpellRange.aStart.Row();
+
+ nVisSpellState = VSPL_DONE; //! only if this is for the visible range
+ }
+ rSpellPos.Set( nCol, nRow, nTab );
+
+ delete pDefaults;
+ delete pEngine; // bevor aStatus out of scope geht
+
+ return bChanged;
+}
+
+
+BOOL ScDocument::ContinueOnlineSpelling()
+{
+ if ( bIdleDisabled || !pDocOptions->IsAutoSpell() || (pShell && pShell->IsReadOnly()) )
+ return FALSE;
+
+ // #i48433# set bInsertingFromOtherDoc flag so there are no broadcasts when PutCell is called
+ // (same behavior as in RemoveAutoSpellObj: just transfer the broadcaster)
+ BOOL bOldInserting = IsInsertingFromOtherDoc();
+ SetInsertingFromOtherDoc( TRUE );
+
+ //! use one EditEngine for both calls
+
+ // #41504# first check visible range
+ BOOL bResult = OnlineSpellInRange( aVisSpellRange, aVisSpellPos, SPELL_MAXTEST_VIS );
+
+ // during first pass through visible range, always continue
+ if ( nVisSpellState == VSPL_START )
+ bResult = TRUE;
+
+ if (bResult)
+ {
+ // if errors found, continue there
+ OnlineSpellInRange( aVisSpellRange, aVisSpellPos, SPELL_MAXTEST_ALL );
+ }
+ else
+ {
+ // if nothing found there, continue with rest of document
+ ScRange aTotalRange( 0,0,0, MAXCOL,MAXROW,MAXTAB );
+ bResult = OnlineSpellInRange( aTotalRange, aOnlineSpellPos, SPELL_MAXTEST_ALL );
+ }
+
+ SetInsertingFromOtherDoc( bOldInserting );
+
+ return bResult;
+}
+
+
+void ScDocument::SetOnlineSpellPos( const ScAddress& rPos )
+{
+ aOnlineSpellPos = rPos;
+
+ // skip visible area for aOnlineSpellPos
+ if ( aVisSpellRange.In( aOnlineSpellPos ) )
+ aOnlineSpellPos = aVisSpellRange.aEnd;
+}
+
+BOOL ScDocument::SetVisibleSpellRange( const ScRange& rNewRange )
+{
+ BOOL bChange = ( aVisSpellRange != rNewRange );
+ if (bChange)
+ {
+ // continue spelling through visible range when scrolling down
+ BOOL bContDown = ( nVisSpellState == VSPL_START && rNewRange.In( aVisSpellPos ) &&
+ rNewRange.aStart.Row() > aVisSpellRange.aStart.Row() &&
+ rNewRange.aStart.Col() == aVisSpellRange.aStart.Col() &&
+ rNewRange.aEnd.Col() == aVisSpellRange.aEnd.Col() );
+
+ aVisSpellRange = rNewRange;
+
+ if ( !bContDown )
+ {
+ aVisSpellPos = aVisSpellRange.aStart;
+ nVisSpellState = VSPL_START;
+ }
+
+ // skip visible area for aOnlineSpellPos
+ if ( aVisSpellRange.In( aOnlineSpellPos ) )
+ aOnlineSpellPos = aVisSpellRange.aEnd;
+ }
+ return bChange;
+}
+
+void ScDocument::RemoveAutoSpellObj()
+{
+ // alle Spelling-Informationen entfernen
+
+ for (SCTAB nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++)
+ pTab[nTab]->RemoveAutoSpellObj();
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScDocument::IdleCheckLinks() // TRUE = demnaechst wieder versuchen
+{
+ BOOL bAnyLeft = FALSE;
+
+ if (pLinkManager)
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScDdeLink))
+ {
+ ScDdeLink* pDdeLink = (ScDdeLink*)pBase;
+ if (pDdeLink->NeedsUpdate())
+ {
+ pDdeLink->TryUpdate();
+ if (pDdeLink->NeedsUpdate()) // war nix?
+ bAnyLeft = TRUE;
+ }
+ }
+ }
+ }
+
+ return bAnyLeft;
+}
+
+void ScDocument::SaveDdeLinks(SvStream& rStream) const
+{
+ // bei 4.0-Export alle mit Modus != DEFAULT weglassen
+ BOOL bExport40 = ( rStream.GetVersion() <= SOFFICE_FILEFORMAT_40 );
+
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+
+ // erstmal zaehlen...
+
+ USHORT nDdeCount = 0;
+ USHORT i;
+ for (i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScDdeLink))
+ if ( !bExport40 || ((ScDdeLink*)pBase)->GetMode() == SC_DDE_DEFAULT )
+ ++nDdeCount;
+ }
+
+ // Header
+
+ ScMultipleWriteHeader aHdr( rStream );
+ rStream << nDdeCount;
+
+ // Links speichern
+
+ for (i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScDdeLink))
+ {
+ ScDdeLink* pLink = (ScDdeLink*)pBase;
+ if ( !bExport40 || pLink->GetMode() == SC_DDE_DEFAULT )
+ pLink->Store( rStream, aHdr );
+ }
+ }
+}
+
+void ScDocument::LoadDdeLinks(SvStream& rStream)
+{
+ ScMultipleReadHeader aHdr( rStream );
+
+ USHORT nCount;
+ rStream >> nCount;
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ScDdeLink* pLink = new ScDdeLink( this, rStream, aHdr );
+ pLinkManager->InsertDDELink( pLink,
+ pLink->GetAppl(), pLink->GetTopic(), pLink->GetItem() );
+ }
+}
+
+BOOL ScDocument::HasDdeLinks() const
+{
+ if (pLinkManager) // Clipboard z.B. hat keinen LinkManager
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ for (USHORT i=0; i<nCount; i++)
+ if ((*rLinks[i])->ISA(ScDdeLink))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void ScDocument::SetInLinkUpdate(BOOL bSet)
+{
+ // called from TableLink and AreaLink
+
+ DBG_ASSERT( bInLinkUpdate != bSet, "SetInLinkUpdate twice" );
+ bInLinkUpdate = bSet;
+}
+
+BOOL ScDocument::IsInLinkUpdate() const
+{
+ return bInLinkUpdate || IsInDdeLinkUpdate();
+}
+
+void ScDocument::UpdateExternalRefLinks()
+{
+ if (!pLinkManager)
+ return;
+
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+
+ bool bAny = false;
+ for (USHORT i = 0; i < nCount; ++i)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ ScExternalRefLink* pRefLink = dynamic_cast<ScExternalRefLink*>(pBase);
+ if (pRefLink)
+ {
+ pRefLink->Update();
+ bAny = true;
+ }
+ }
+ if (bAny)
+ {
+ TrackFormulas();
+ pShell->Broadcast( SfxSimpleHint(FID_DATACHANGED) );
+ ResetChanged( ScRange(0, 0, 0, MAXCOL, MAXROW, MAXTAB) );
+ }
+}
+
+void ScDocument::UpdateDdeLinks()
+{
+ if (pLinkManager)
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ USHORT i;
+
+ // #49226# falls das Updaten laenger dauert, erstmal alle Werte
+ // zuruecksetzen, damit nichts altes (falsches) stehen bleibt
+ BOOL bAny = FALSE;
+ for (i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScDdeLink))
+ {
+ ((ScDdeLink*)pBase)->ResetValue();
+ bAny = TRUE;
+ }
+ }
+ if (bAny)
+ {
+ // Formeln berechnen und painten wie im TrackTimeHdl
+ TrackFormulas();
+ pShell->Broadcast( SfxSimpleHint( FID_DATACHANGED ) );
+ ResetChanged( ScRange(0,0,0,MAXCOL,MAXROW,MAXTAB) );
+
+ // wenn FID_DATACHANGED irgendwann mal asynchron werden sollte
+ // (z.B. mit Invalidate am Window), muss hier ein Update erzwungen werden.
+ }
+
+ // nun wirklich updaten...
+ for (i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScDdeLink))
+ ((ScDdeLink*)pBase)->TryUpdate(); // bei DDE-Links TryUpdate statt Update
+ }
+ }
+}
+
+BOOL ScDocument::UpdateDdeLink( const String& rAppl, const String& rTopic, const String& rItem )
+{
+ // fuer refresh() per StarOne Api
+ // ResetValue() fuer einzelnen Link nicht noetig
+ //! wenn's mal alles asynchron wird, aber auch hier
+
+ BOOL bFound = FALSE;
+ if (pLinkManager)
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScDdeLink))
+ {
+ ScDdeLink* pDdeLink = (ScDdeLink*)pBase;
+ if ( pDdeLink->GetAppl() == rAppl &&
+ pDdeLink->GetTopic() == rTopic &&
+ pDdeLink->GetItem() == rItem )
+ {
+ pDdeLink->TryUpdate();
+ bFound = TRUE; // koennen theoretisch mehrere sein (Mode), darum weitersuchen
+ }
+ }
+ }
+ }
+ return bFound;
+}
+
+void ScDocument::DisconnectDdeLinks()
+{
+ if (pLinkManager)
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScDdeLink))
+ pBase->Disconnect(); // bleibt im LinkManager eingetragen
+ }
+ }
+}
+
+void ScDocument::CopyDdeLinks( ScDocument* pDestDoc ) const
+{
+ if (bIsClip) // aus Stream erzeugen
+ {
+ if (pClipData)
+ {
+ pClipData->Seek(0);
+ pDestDoc->LoadDdeLinks(*pClipData);
+ }
+ }
+ else if (pLinkManager) // Links direkt kopieren
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScDdeLink))
+ {
+ ScDdeLink* pNew = new ScDdeLink( pDestDoc, *(ScDdeLink*)pBase );
+
+ pDestDoc->pLinkManager->InsertDDELink( pNew,
+ pNew->GetAppl(), pNew->GetTopic(), pNew->GetItem() );
+ }
+ }
+ }
+}
+
+USHORT ScDocument::GetDdeLinkCount() const
+{
+ USHORT nDdeCount = 0;
+ if (pLinkManager)
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ for (USHORT i=0; i<nCount; i++)
+ if ((*rLinks[i])->ISA(ScDdeLink))
+ ++nDdeCount;
+ }
+ return nDdeCount;
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+/** Tries to find the specified DDE link.
+ @param pnDdePos (out-param) if not 0, the index of the DDE link is returned here
+ (does not include other links from link manager).
+ @return The DDE link, if it exists, otherwise 0. */
+ScDdeLink* lclGetDdeLink(
+ const SvxLinkManager* pLinkManager,
+ const String& rAppl, const String& rTopic, const String& rItem, BYTE nMode,
+ USHORT* pnDdePos = NULL )
+{
+ if( pLinkManager )
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ if( pnDdePos ) *pnDdePos = 0;
+ for( USHORT nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ ::sfx2::SvBaseLink* pLink = *rLinks[ nIndex ];
+ if( ScDdeLink* pDdeLink = PTR_CAST( ScDdeLink, pLink ) )
+ {
+ if( (pDdeLink->GetAppl() == rAppl) &&
+ (pDdeLink->GetTopic() == rTopic) &&
+ (pDdeLink->GetItem() == rItem) &&
+ ((nMode == SC_DDE_IGNOREMODE) || (nMode == pDdeLink->GetMode())) )
+ return pDdeLink;
+ if( pnDdePos ) ++*pnDdePos;
+ }
+ }
+ }
+ return NULL;
+}
+
+/** Returns a pointer to the specified DDE link.
+ @param nDdePos Index of the DDE link (does not include other links from link manager).
+ @return The DDE link, if it exists, otherwise 0. */
+ScDdeLink* lclGetDdeLink( const SvxLinkManager* pLinkManager, USHORT nDdePos )
+{
+ if( pLinkManager )
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ USHORT nDdeIndex = 0; // counts only the DDE links
+ for( USHORT nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ ::sfx2::SvBaseLink* pLink = *rLinks[ nIndex ];
+ if( ScDdeLink* pDdeLink = PTR_CAST( ScDdeLink, pLink ) )
+ {
+ if( nDdeIndex == nDdePos )
+ return pDdeLink;
+ ++nDdeIndex;
+ }
+ }
+ }
+ return NULL;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+bool ScDocument::FindDdeLink( const String& rAppl, const String& rTopic, const String& rItem, BYTE nMode, USHORT& rnDdePos )
+{
+ return lclGetDdeLink( pLinkManager, rAppl, rTopic, rItem, nMode, &rnDdePos ) != NULL;
+}
+
+bool ScDocument::GetDdeLinkData( USHORT nDdePos, String& rAppl, String& rTopic, String& rItem ) const
+{
+ if( const ScDdeLink* pDdeLink = lclGetDdeLink( pLinkManager, nDdePos ) )
+ {
+ rAppl = pDdeLink->GetAppl();
+ rTopic = pDdeLink->GetTopic();
+ rItem = pDdeLink->GetItem();
+ return true;
+ }
+ return false;
+}
+
+bool ScDocument::GetDdeLinkMode( USHORT nDdePos, BYTE& rnMode ) const
+{
+ if( const ScDdeLink* pDdeLink = lclGetDdeLink( pLinkManager, nDdePos ) )
+ {
+ rnMode = pDdeLink->GetMode();
+ return true;
+ }
+ return false;
+}
+
+const ScMatrix* ScDocument::GetDdeLinkResultMatrix( USHORT nDdePos ) const
+{
+ const ScDdeLink* pDdeLink = lclGetDdeLink( pLinkManager, nDdePos );
+ return pDdeLink ? pDdeLink->GetResult() : NULL;
+}
+
+bool ScDocument::CreateDdeLink( const String& rAppl, const String& rTopic, const String& rItem, BYTE nMode, ScMatrix* pResults )
+{
+ /* Create a DDE link without updating it (i.e. for Excel import), to prevent
+ unwanted connections. First try to find existing link. Set result array
+ on existing and new links. */
+ //! store DDE links additionally at document (for efficiency)?
+ DBG_ASSERT( nMode != SC_DDE_IGNOREMODE, "ScDocument::CreateDdeLink - SC_DDE_IGNOREMODE not allowed here" );
+ if( pLinkManager && (nMode != SC_DDE_IGNOREMODE) )
+ {
+ ScDdeLink* pDdeLink = lclGetDdeLink( pLinkManager, rAppl, rTopic, rItem, nMode );
+ if( !pDdeLink )
+ {
+ // create a new DDE link, but without TryUpdate
+ pDdeLink = new ScDdeLink( this, rAppl, rTopic, rItem, nMode );
+ pLinkManager->InsertDDELink( pDdeLink, rAppl, rTopic, rItem );
+ }
+
+ // insert link results
+ if( pResults )
+ pDdeLink->SetResult( pResults );
+
+ return true;
+ }
+ return false;
+}
+
+bool ScDocument::SetDdeLinkResultMatrix( USHORT nDdePos, ScMatrix* pResults )
+{
+ if( ScDdeLink* pDdeLink = lclGetDdeLink( pLinkManager, nDdePos ) )
+ {
+ pDdeLink->SetResult( pResults );
+ return true;
+ }
+ return false;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScDocument::HasAreaLinks() const
+{
+ if (pLinkManager) // Clipboard z.B. hat keinen LinkManager
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ for (USHORT i=0; i<nCount; i++)
+ if ((*rLinks[i])->ISA(ScAreaLink))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void ScDocument::UpdateAreaLinks()
+{
+ if (pLinkManager)
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScAreaLink))
+ pBase->Update();
+ }
+ }
+}
+
+void ScDocument::DeleteAreaLinksOnTab( SCTAB nTab )
+{
+ if (pLinkManager)
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nPos = 0;
+ while ( nPos < rLinks.Count() )
+ {
+ const ::sfx2::SvBaseLink* pBase = *rLinks[nPos];
+ if ( pBase->ISA(ScAreaLink) &&
+ static_cast<const ScAreaLink*>(pBase)->GetDestArea().aStart.Tab() == nTab )
+ pLinkManager->Remove( nPos );
+ else
+ ++nPos;
+ }
+ }
+}
+
+void ScDocument::UpdateRefAreaLinks( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ if (pLinkManager)
+ {
+ bool bAnyUpdate = false;
+
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ USHORT nCount = rLinks.Count();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = *rLinks[i];
+ if (pBase->ISA(ScAreaLink))
+ {
+ ScAreaLink* pLink = (ScAreaLink*) pBase;
+ ScRange aOutRange = pLink->GetDestArea();
+
+ SCCOL nCol1 = aOutRange.aStart.Col();
+ SCROW nRow1 = aOutRange.aStart.Row();
+ SCTAB nTab1 = aOutRange.aStart.Tab();
+ SCCOL nCol2 = aOutRange.aEnd.Col();
+ SCROW nRow2 = aOutRange.aEnd.Row();
+ SCTAB nTab2 = aOutRange.aEnd.Tab();
+
+ ScRefUpdateRes eRes =
+ ScRefUpdate::Update( this, eUpdateRefMode,
+ rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
+ nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if ( eRes != UR_NOTHING )
+ {
+ pLink->SetDestArea( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
+ bAnyUpdate = true;
+ }
+ }
+ }
+
+ if ( bAnyUpdate )
+ {
+ // #i52120# Look for duplicates (after updating all positions).
+ // If several links start at the same cell, the one with the lower index is removed
+ // (file format specifies only one link definition for a cell).
+
+ USHORT nFirstIndex = 0;
+ while ( nFirstIndex < nCount )
+ {
+ bool bFound = false;
+ ::sfx2::SvBaseLink* pFirst = *rLinks[nFirstIndex];
+ if ( pFirst->ISA(ScAreaLink) )
+ {
+ ScAddress aFirstPos = static_cast<ScAreaLink*>(pFirst)->GetDestArea().aStart;
+ for ( USHORT nSecondIndex = nFirstIndex + 1; nSecondIndex < nCount && !bFound; ++nSecondIndex )
+ {
+ ::sfx2::SvBaseLink* pSecond = *rLinks[nSecondIndex];
+ if ( pSecond->ISA(ScAreaLink) &&
+ static_cast<ScAreaLink*>(pSecond)->GetDestArea().aStart == aFirstPos )
+ {
+ // remove the first link, exit the inner loop, don't increment nFirstIndex
+ pLinkManager->Remove( pFirst );
+ nCount = rLinks.Count();
+ bFound = true;
+ }
+ }
+ }
+ if (!bFound)
+ ++nFirstIndex;
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+
+// TimerDelays etc.
+void ScDocument::KeyInput( const KeyEvent& )
+{
+ if ( pChartListenerCollection->GetCount() )
+ pChartListenerCollection->StartTimer();
+ if( apTemporaryChartLock.get() )
+ apTemporaryChartLock->StartOrContinueLocking();
+}
+
+// ----------------------------------------------------------------------------
+
+BOOL ScDocument::CheckMacroWarn()
+{
+ // The check for macro configuration, macro warning and disabling is now handled
+ // in SfxObjectShell::AdjustMacroMode, called by SfxObjectShell::CallBasic.
+
+ return TRUE;
+}
+
+//------------------------------------------------------------------------
+
+SfxBindings* ScDocument::GetViewBindings()
+{
+ // used to invalidate slots after changes to this document
+
+ if ( !pShell )
+ return NULL; // no ObjShell -> no view
+
+ // first check current view
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if ( pViewFrame && pViewFrame->GetObjectShell() != pShell ) // wrong document?
+ pViewFrame = NULL;
+
+ // otherwise use first view for this doc
+ if ( !pViewFrame )
+ pViewFrame = SfxViewFrame::GetFirst( pShell );
+
+ if (pViewFrame)
+ return &pViewFrame->GetBindings();
+ else
+ return NULL;
+}
+
+//------------------------------------------------------------------------
+
+void lcl_TransliterateEditEngine( ScEditEngineDefaulter& rEngine,
+ utl::TransliterationWrapper& rTranslitarationWrapper,
+ BOOL bConsiderLanguage, ScDocument* pDoc )
+{
+ //! should use TransliterateText method of EditEngine instead, when available!
+
+ sal_uInt16 nLanguage = LANGUAGE_SYSTEM;
+
+ USHORT nParCount = rEngine.GetParagraphCount();
+ for (USHORT nPar=0; nPar<nParCount; nPar++)
+ {
+ SvUShorts aPortions;
+ rEngine.GetPortions( (USHORT)nPar, aPortions );
+
+ for ( USHORT nPos = aPortions.Count(); nPos; )
+ {
+ --nPos;
+ USHORT nEnd = aPortions.GetObject( nPos );
+ USHORT nStart = nPos ? aPortions.GetObject( nPos - 1 ) : 0;
+
+ ESelection aSel( nPar, nStart, nPar, nEnd );
+ String aOldStr = rEngine.GetText( aSel );
+ SfxItemSet aAttr = rEngine.GetAttribs( aSel );
+
+ if ( aAttr.GetItemState( EE_FEATURE_FIELD ) != SFX_ITEM_ON ) // fields are not touched
+ {
+ if ( bConsiderLanguage )
+ {
+ BYTE nScript = pDoc->GetStringScriptType( aOldStr );
+ USHORT nWhich = ( nScript == SCRIPTTYPE_ASIAN ) ? EE_CHAR_LANGUAGE_CJK :
+ ( ( nScript == SCRIPTTYPE_COMPLEX ) ? EE_CHAR_LANGUAGE_CTL :
+ EE_CHAR_LANGUAGE );
+ nLanguage = ((const SvxLanguageItem&)aAttr.Get(nWhich)).GetValue();
+ }
+
+ com::sun::star::uno::Sequence<sal_Int32> aOffsets;
+ String aNewStr = rTranslitarationWrapper.transliterate( aOldStr, nLanguage, 0, aOldStr.Len(), &aOffsets );
+
+ if ( aNewStr != aOldStr )
+ {
+ // replace string, keep attributes
+
+ rEngine.QuickInsertText( aNewStr, aSel );
+ aSel.nEndPos = aSel.nStartPos + aNewStr.Len();
+ rEngine.QuickSetAttribs( aAttr, aSel );
+ }
+ }
+ }
+ }
+}
+
+void ScDocument::TransliterateText( const ScMarkData& rMultiMark, sal_Int32 nType )
+{
+ DBG_ASSERT( rMultiMark.IsMultiMarked(), "TransliterateText: no selection" );
+
+ utl::TransliterationWrapper aTranslitarationWrapper( xServiceManager, nType );
+ BOOL bConsiderLanguage = aTranslitarationWrapper.needLanguageForTheMode();
+ sal_uInt16 nLanguage = LANGUAGE_SYSTEM;
+
+ ScEditEngineDefaulter* pEngine = NULL; // not using pEditEngine member because of defaults
+
+ SCTAB nCount = GetTableCount();
+ for (SCTAB nTab = 0; nTab < nCount; nTab++)
+ if ( pTab[nTab] && rMultiMark.GetTableSelect(nTab) )
+ {
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+
+ BOOL bFound = rMultiMark.IsCellMarked( nCol, nRow );
+ if (!bFound)
+ bFound = GetNextMarkedCell( nCol, nRow, nTab, rMultiMark );
+
+ while (bFound)
+ {
+ const ScBaseCell* pCell = GetCell( ScAddress( nCol, nRow, nTab ) );
+ CellType eType = pCell ? pCell->GetCellType() : CELLTYPE_NONE;
+
+ if ( eType == CELLTYPE_STRING )
+ {
+ String aOldStr;
+ ((const ScStringCell*)pCell)->GetString(aOldStr);
+ xub_StrLen nOldLen = aOldStr.Len();
+
+ if ( bConsiderLanguage )
+ {
+ BYTE nScript = GetStringScriptType( aOldStr ); //! cell script type?
+ USHORT nWhich = ( nScript == SCRIPTTYPE_ASIAN ) ? ATTR_CJK_FONT_LANGUAGE :
+ ( ( nScript == SCRIPTTYPE_COMPLEX ) ? ATTR_CTL_FONT_LANGUAGE :
+ ATTR_FONT_LANGUAGE );
+ nLanguage = ((const SvxLanguageItem*)GetAttr( nCol, nRow, nTab, nWhich ))->GetValue();
+ }
+
+ com::sun::star::uno::Sequence<sal_Int32> aOffsets;
+ String aNewStr = aTranslitarationWrapper.transliterate( aOldStr, nLanguage, 0, nOldLen, &aOffsets );
+
+ if ( aNewStr != aOldStr )
+ PutCell( nCol, nRow, nTab, new ScStringCell( aNewStr ) );
+ }
+ else if ( eType == CELLTYPE_EDIT )
+ {
+ if (!pEngine)
+ pEngine = new ScFieldEditEngine( GetEnginePool(), GetEditPool() );
+
+ // defaults from cell attributes must be set so right language is used
+ const ScPatternAttr* pPattern = GetPattern( nCol, nRow, nTab );
+ SfxItemSet* pDefaults = new SfxItemSet( pEngine->GetEmptyItemSet() );
+ pPattern->FillEditItemSet( pDefaults );
+ pEngine->SetDefaults( pDefaults, TRUE );
+
+ const EditTextObject* pData = ((const ScEditCell*)pCell)->GetData();
+ pEngine->SetText( *pData );
+
+ pEngine->ClearModifyFlag();
+
+ lcl_TransliterateEditEngine( *pEngine, aTranslitarationWrapper, bConsiderLanguage, this );
+
+ if ( pEngine->IsModified() )
+ {
+ ScEditAttrTester aTester( pEngine );
+ if ( aTester.NeedsObject() )
+ {
+ // remove defaults (paragraph attributes) before creating text object
+ SfxItemSet* pEmpty = new SfxItemSet( pEngine->GetEmptyItemSet() );
+ pEngine->SetDefaults( pEmpty, TRUE );
+
+ EditTextObject* pNewData = pEngine->CreateTextObject();
+ PutCell( nCol, nRow, nTab,
+ new ScEditCell( pNewData, this, pEngine->GetEditTextObjectPool() ) );
+ delete pNewData;
+ }
+ else
+ {
+ String aNewStr = pEngine->GetText();
+ PutCell( nCol, nRow, nTab, new ScStringCell( aNewStr ) );
+ }
+ }
+ }
+
+ bFound = GetNextMarkedCell( nCol, nRow, nTab, rMultiMark );
+ }
+ }
+
+ delete pEngine;
+}
+
diff --git a/sc/source/core/data/documen9.cxx b/sc/source/core/data/documen9.cxx
new file mode 100644
index 000000000000..06a683b0bf72
--- /dev/null
+++ b/sc/source/core/data/documen9.cxx
@@ -0,0 +1,883 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: documen9.cxx,v $
+ * $Revision: 1.43.52.5 $
+ *
+ * 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 <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XClassifiedObject.hpp>
+#include <com/sun/star/chart2/data/XDataReceiver.hpp>
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/eeitem.hxx>
+
+#include <sot/exchange.hxx>
+#include <svx/akrnitem.hxx>
+#include <svx/fontitem.hxx>
+#include <svx/forbiddencharacterstable.hxx>
+#include <svx/langitem.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/xtable.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/printer.hxx>
+#include <svtools/saveopt.hxx>
+#include <svtools/pathoptions.hxx>
+
+#include "document.hxx"
+#include "docoptio.hxx"
+#include "table.hxx"
+#include "drwlayer.hxx"
+#include "markdata.hxx"
+#include "patattr.hxx"
+#include "rechead.hxx"
+#include "poolhelp.hxx"
+#include "docpool.hxx"
+#include "chartarr.hxx"
+#include "detfunc.hxx" // for UpdateAllComments
+#include "editutil.hxx"
+#include "postit.hxx"
+
+using namespace ::com::sun::star;
+
+// -----------------------------------------------------------------------
+
+
+SfxBroadcaster* ScDocument::GetDrawBroadcaster()
+{
+ return pDrawLayer;
+}
+
+void ScDocument::BeginDrawUndo()
+{
+ if (pDrawLayer)
+ pDrawLayer->BeginCalcUndo();
+}
+
+XColorTable* ScDocument::GetColorTable()
+{
+ if (pDrawLayer)
+ return pDrawLayer->GetColorTable();
+ else
+ {
+ if (!pColorTable)
+ {
+ SvtPathOptions aPathOpt;
+ pColorTable = new XColorTable( aPathOpt.GetPalettePath() );
+ }
+
+ return pColorTable;
+ }
+}
+
+BOOL lcl_AdjustRanges( ScRangeList& rRanges, SCTAB nSource, SCTAB nDest, SCTAB nTabCount )
+{
+ //! if multiple sheets are copied, update references into the other copied sheets?
+
+ BOOL bChanged = FALSE;
+
+ ULONG nCount = rRanges.Count();
+ for (ULONG i=0; i<nCount; i++)
+ {
+ ScRange* pRange = rRanges.GetObject(i);
+ if ( pRange->aStart.Tab() == nSource && pRange->aEnd.Tab() == nSource )
+ {
+ pRange->aStart.SetTab( nDest );
+ pRange->aEnd.SetTab( nDest );
+ bChanged = TRUE;
+ }
+ if ( pRange->aStart.Tab() >= nTabCount )
+ {
+ pRange->aStart.SetTab( nTabCount > 0 ? ( nTabCount - 1 ) : 0 );
+ bChanged = TRUE;
+ }
+ if ( pRange->aEnd.Tab() >= nTabCount )
+ {
+ pRange->aEnd.SetTab( nTabCount > 0 ? ( nTabCount - 1 ) : 0 );
+ bChanged = TRUE;
+ }
+ }
+
+ return bChanged;
+}
+
+void ScDocument::TransferDrawPage(ScDocument* pSrcDoc, SCTAB nSrcPos, SCTAB nDestPos)
+{
+ if (pDrawLayer && pSrcDoc->pDrawLayer)
+ {
+ SdrPage* pOldPage = pSrcDoc->pDrawLayer->GetPage(static_cast<sal_uInt16>(nSrcPos));
+ SdrPage* pNewPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nDestPos));
+
+ if (pOldPage && pNewPage)
+ {
+ SdrObjListIter aIter( *pOldPage, IM_FLAT );
+ SdrObject* pOldObject = aIter.Next();
+ while (pOldObject)
+ {
+ // #116235#
+ SdrObject* pNewObject = pOldObject->Clone();
+ // SdrObject* pNewObject = pOldObject->Clone( pNewPage, pDrawLayer );
+ pNewObject->SetModel(pDrawLayer);
+ pNewObject->SetPage(pNewPage);
+
+ pNewObject->NbcMove(Size(0,0));
+ pNewPage->InsertObject( pNewObject );
+
+ if (pDrawLayer->IsRecording())
+ pDrawLayer->AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) );
+
+ // #71726# if it's a chart, make sure the data references are valid
+ // (this must be after InsertObject!)
+
+ if ( pNewObject->GetObjIdentifier() == OBJ_OLE2 )
+ {
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pNewObject)->GetObjRef();
+ uno::Reference< embed::XClassifiedObject > xClassified( xIPObj, uno::UNO_QUERY );
+ SvGlobalName aObjectClassName;
+ if ( xClassified.is() )
+ {
+ try {
+ aObjectClassName = SvGlobalName( xClassified->getClassID() );
+ } catch( uno::Exception& )
+ {
+ // TODO: handle error?
+ }
+ }
+
+ if ( xIPObj.is() && SotExchange::IsChart( aObjectClassName ) )
+ {
+ String aChartName = ((SdrOle2Obj*)pNewObject)->GetPersistName();
+
+ uno::Reference< chart2::XChartDocument > xChartDoc( GetChartByName( aChartName ) );
+ uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, uno::UNO_QUERY );
+ if( xChartDoc.is() && xReceiver.is() )
+ {
+ if( !xChartDoc->hasInternalDataProvider() )
+ {
+ ::std::vector< ScRangeList > aRangesVector;
+ GetChartRanges( aChartName, aRangesVector, pSrcDoc );
+
+ ::std::vector< ScRangeList >::iterator aIt( aRangesVector.begin() );
+ for( ; aIt!=aRangesVector.end(); aIt++ )
+ {
+ ScRangeList& rScRangeList( *aIt );
+ lcl_AdjustRanges( rScRangeList, nSrcPos, nDestPos, GetTableCount() );
+ }
+ SetChartRanges( aChartName, aRangesVector );
+ }
+ }
+ }
+ }
+
+ pOldObject = aIter.Next();
+ }
+ }
+ }
+}
+
+void ScDocument::InitDrawLayer( SfxObjectShell* pDocShell )
+{
+ if (pDocShell && !pShell)
+ pShell = pDocShell;
+
+// DBG_ASSERT(pShell,"InitDrawLayer ohne Shell");
+
+ if (!pDrawLayer)
+ {
+ String aName;
+ if ( pShell && !pShell->IsLoading() ) // #88438# don't call GetTitle while loading
+ aName = pShell->GetTitle();
+ pDrawLayer = new ScDrawLayer( this, aName );
+ if (pLinkManager)
+ pDrawLayer->SetLinkManager( pLinkManager );
+
+ // Drawing pages are accessed by table number, so they must also be present
+ // for preceding table numbers, even if the tables aren't allocated
+ // (important for clipboard documents).
+
+ SCTAB nDrawPages = 0;
+ SCTAB nTab;
+ for (nTab=0; nTab<=MAXTAB; nTab++)
+ if (pTab[nTab])
+ nDrawPages = nTab + 1; // needed number of pages
+
+ for (nTab=0; nTab<nDrawPages; nTab++)
+ {
+ pDrawLayer->ScAddPage( nTab ); // always add page, with or without the table
+ if (pTab[nTab])
+ {
+ String aTabName;
+ pTab[nTab]->GetName(aTabName);
+ pDrawLayer->ScRenamePage( nTab, aTabName );
+
+ pTab[nTab]->SetDrawPageSize(); // #54782# sofort die richtige Groesse
+#if 0
+ ULONG nx = (ULONG) ((double) (MAXCOL+1) * STD_COL_WIDTH * HMM_PER_TWIPS );
+ ULONG ny = (ULONG) ((double) (MAXROW+1) * ScGlobal::nStdRowHeight * HMM_PER_TWIPS );
+ pDrawLayer->SetPageSize( nTab, Size( nx, ny ) );
+#endif
+ }
+ }
+
+ pDrawLayer->SetDefaultTabulator( GetDocOptions().GetTabDistance() );
+
+ UpdateDrawPrinter();
+ UpdateDrawDefaults();
+ UpdateDrawLanguages();
+ if (bImportingXML)
+ pDrawLayer->EnableAdjust(FALSE);
+
+ pDrawLayer->SetForbiddenCharsTable( xForbiddenCharacters );
+ pDrawLayer->SetCharCompressType( GetAsianCompression() );
+ pDrawLayer->SetKernAsianPunctuation( GetAsianKerning() );
+ }
+}
+
+void ScDocument::UpdateDrawLanguages()
+{
+ if (pDrawLayer)
+ {
+ SfxItemPool& rDrawPool = pDrawLayer->GetItemPool();
+ rDrawPool.SetPoolDefaultItem( SvxLanguageItem( eLanguage, EE_CHAR_LANGUAGE ) );
+ rDrawPool.SetPoolDefaultItem( SvxLanguageItem( eCjkLanguage, EE_CHAR_LANGUAGE_CJK ) );
+ rDrawPool.SetPoolDefaultItem( SvxLanguageItem( eCtlLanguage, EE_CHAR_LANGUAGE_CTL ) );
+ }
+}
+
+void ScDocument::UpdateDrawDefaults()
+{
+ // drawing layer defaults that are set for new documents (if InitNew was called)
+
+ if ( pDrawLayer && bSetDrawDefaults )
+ {
+ SfxItemPool& rDrawPool = pDrawLayer->GetItemPool();
+ rDrawPool.SetPoolDefaultItem( SvxAutoKernItem( TRUE, EE_CHAR_PAIRKERNING ) );
+ }
+}
+
+void ScDocument::UpdateDrawPrinter()
+{
+ if (pDrawLayer)
+ {
+ // use the printer even if IsValid is false
+ // Application::GetDefaultDevice causes trouble with changing MapModes
+
+// OutputDevice* pRefDev = GetPrinter();
+// pRefDev->SetMapMode( MAP_100TH_MM );
+ pDrawLayer->SetRefDevice(GetRefDevice());
+ }
+}
+
+sal_Bool ScDocument::IsChart( const SdrObject* pObject )
+{
+ // #109985#
+ // IsChart() implementation moved to svx drawinglayer
+ if(pObject && OBJ_OLE2 == pObject->GetObjIdentifier())
+ {
+ return ((SdrOle2Obj*)pObject)->IsChart();
+ }
+
+ return sal_False;
+}
+
+IMPL_LINK_INLINE_START( ScDocument, GetUserDefinedColor, USHORT *, pColorIndex )
+{
+ return (long) &((GetColorTable()->GetColor(*pColorIndex))->GetColor());
+}
+IMPL_LINK_INLINE_END( ScDocument, GetUserDefinedColor, USHORT *, pColorIndex )
+
+void ScDocument::DeleteDrawLayer()
+{
+ delete pDrawLayer;
+}
+
+void ScDocument::DeleteColorTable()
+{
+ delete pColorTable;
+}
+
+BOOL ScDocument::DrawGetPrintArea( ScRange& rRange, BOOL bSetHor, BOOL bSetVer ) const
+{
+ return pDrawLayer->GetPrintArea( rRange, bSetHor, bSetVer );
+}
+
+void ScDocument::DrawMovePage( USHORT nOldPos, USHORT nNewPos )
+{
+ pDrawLayer->ScMovePage(nOldPos,nNewPos);
+}
+
+void ScDocument::DrawCopyPage( USHORT nOldPos, USHORT nNewPos )
+{
+ // angelegt wird die Page schon im ScTable ctor
+ pDrawLayer->ScCopyPage( nOldPos, nNewPos, FALSE );
+}
+
+void ScDocument::DeleteObjectsInArea( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark )
+{
+ if (!pDrawLayer)
+ return;
+
+ SCTAB nTabCount = GetTableCount();
+ for (SCTAB nTab=0; nTab<=nTabCount; nTab++)
+ if (pTab[nTab] && rMark.GetTableSelect(nTab))
+ pDrawLayer->DeleteObjectsInArea( nTab, nCol1, nRow1, nCol2, nRow2 );
+}
+
+void ScDocument::DeleteObjectsInSelection( const ScMarkData& rMark )
+{
+ if (!pDrawLayer)
+ return;
+
+ pDrawLayer->DeleteObjectsInSelection( rMark );
+}
+
+BOOL ScDocument::HasOLEObjectsInArea( const ScRange& rRange, const ScMarkData* pTabMark )
+{
+ // pTabMark is used only for selected tables. If pTabMark is 0, all tables of rRange are used.
+
+ if (!pDrawLayer)
+ return FALSE;
+
+ SCTAB nStartTab = 0;
+ SCTAB nEndTab = MAXTAB;
+ if ( !pTabMark )
+ {
+ nStartTab = rRange.aStart.Tab();
+ nEndTab = rRange.aEnd.Tab();
+ }
+
+ for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++)
+ {
+ if ( !pTabMark || pTabMark->GetTableSelect(nTab) )
+ {
+ Rectangle aMMRect = GetMMRect( rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
+
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_OLE2 &&
+ aMMRect.IsInside( pObject->GetCurrentBoundRect() ) )
+ return TRUE;
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+void ScDocument::StartAnimations( SCTAB nTab, Window* pWin )
+{
+ if (!pDrawLayer)
+ return;
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (!pPage)
+ return;
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if (pObject->ISA(SdrGrafObj))
+ {
+ SdrGrafObj* pGrafObj = (SdrGrafObj*)pObject;
+ if ( pGrafObj->IsAnimated() )
+ {
+ const Rectangle& rRect = pGrafObj->GetCurrentBoundRect();
+ pGrafObj->StartAnimation( pWin, rRect.TopLeft(), rRect.GetSize() );
+ }
+ }
+ pObject = aIter.Next();
+ }
+}
+
+//UNUSED2008-05 void ScDocument::RefreshNoteFlags()
+//UNUSED2008-05 {
+//UNUSED2008-05 if (!pDrawLayer)
+//UNUSED2008-05 return;
+//UNUSED2008-05
+//UNUSED2008-05 BOOL bAnyIntObj = FALSE;
+//UNUSED2008-05 SCTAB nTab;
+//UNUSED2008-05 ScPostIt aNote(this);
+//UNUSED2008-05 for (nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++)
+//UNUSED2008-05 {
+//UNUSED2008-05 SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+//UNUSED2008-05 DBG_ASSERT(pPage,"Page ?");
+//UNUSED2008-05 if (pPage)
+//UNUSED2008-05 {
+//UNUSED2008-05 SdrObjListIter aIter( *pPage, IM_FLAT );
+//UNUSED2008-05 SdrObject* pObject = aIter.Next();
+//UNUSED2008-05 while (pObject)
+//UNUSED2008-05 {
+//UNUSED2008-05 if ( pObject->GetLayer() == SC_LAYER_INTERN )
+//UNUSED2008-05 {
+//UNUSED2008-05 bAnyIntObj = TRUE; // for all internal objects, including detective
+//UNUSED2008-05
+//UNUSED2008-05 if ( pObject->ISA( SdrCaptionObj ) )
+//UNUSED2008-05 {
+//UNUSED2008-05 ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
+//UNUSED2008-05 if ( pData )
+//UNUSED2008-05 {
+//UNUSED2008-05 if ( GetNote( pData->aStt.Col(), pData->aStt.Row(), nTab, aNote))
+//UNUSED2008-05 if ( !aNote.IsShown() )
+//UNUSED2008-05 {
+//UNUSED2008-05 aNote.SetShown(TRUE);
+//UNUSED2008-05 SetNote( pData->aStt.Col(), pData->aStt.Row(), nTab, aNote);
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 pObject = aIter.Next();
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05 if (bAnyIntObj)
+//UNUSED2008-05 {
+//UNUSED2008-05 // update attributes for all note objects and the colors of detective objects
+//UNUSED2008-05 // (we don't know with which settings the file was created)
+//UNUSED2008-05
+//UNUSED2008-05 ScDetectiveFunc aFunc( this, 0 );
+//UNUSED2008-05 aFunc.UpdateAllComments();
+//UNUSED2008-05 aFunc.UpdateAllArrowColors();
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+
+BOOL ScDocument::HasBackgroundDraw( SCTAB nTab, const Rectangle& rMMRect )
+{
+ // Gibt es Objekte auf dem Hintergrund-Layer, die (teilweise) von rMMRect
+ // betroffen sind?
+ // (fuer Drawing-Optimierung, vor dem Hintergrund braucht dann nicht geloescht
+ // zu werden)
+
+ if (!pDrawLayer)
+ return FALSE;
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (!pPage)
+ return FALSE;
+
+ BOOL bFound = FALSE;
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ if ( pObject->GetLayer() == SC_LAYER_BACK && pObject->GetCurrentBoundRect().IsOver( rMMRect ) )
+ bFound = TRUE;
+ pObject = aIter.Next();
+ }
+
+ return bFound;
+}
+
+BOOL ScDocument::HasAnyDraw( SCTAB nTab, const Rectangle& rMMRect )
+{
+ // Gibt es ueberhaupt Objekte, die (teilweise) von rMMRect
+ // betroffen sind?
+ // (um leere Seiten beim Drucken zu erkennen)
+
+ if (!pDrawLayer)
+ return FALSE;
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (!pPage)
+ return FALSE;
+
+ BOOL bFound = FALSE;
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ if ( pObject->GetCurrentBoundRect().IsOver( rMMRect ) )
+ bFound = TRUE;
+ pObject = aIter.Next();
+ }
+
+ return bFound;
+}
+
+void ScDocument::EnsureGraphicNames()
+{
+ if (pDrawLayer)
+ pDrawLayer->EnsureGraphicNames();
+}
+
+SdrObject* ScDocument::GetObjectAtPoint( SCTAB nTab, const Point& rPos )
+{
+ // fuer Drag&Drop auf Zeichenobjekt
+
+ SdrObject* pFound = NULL;
+ if (pDrawLayer && pTab[nTab])
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetCurrentBoundRect().IsInside(rPos) )
+ {
+ // Intern interessiert gar nicht
+ // Objekt vom Back-Layer nur, wenn kein Objekt von anderem Layer getroffen
+
+ SdrLayerID nLayer = pObject->GetLayer();
+ if ( (nLayer != SC_LAYER_INTERN) && (nLayer != SC_LAYER_HIDDEN) )
+ {
+ if ( nLayer != SC_LAYER_BACK ||
+ !pFound || pFound->GetLayer() == SC_LAYER_BACK )
+ {
+ pFound = pObject;
+ }
+ }
+ }
+ // weitersuchen -> letztes (oberstes) getroffenes Objekt nehmen
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+ return pFound;
+}
+
+BOOL ScDocument::IsPrintEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, BOOL bLeftIsEmpty,
+ ScRange* pLastRange, Rectangle* pLastMM ) const
+{
+ if (!IsBlockEmpty( nTab, nStartCol, nStartRow, nEndCol, nEndRow ))
+ return FALSE;
+
+ ScDocument* pThis = (ScDocument*)this; //! GetMMRect / HasAnyDraw etc. const !!!
+
+ Rectangle aMMRect;
+ if ( pLastRange && pLastMM && nTab == pLastRange->aStart.Tab() &&
+ nStartRow == pLastRange->aStart.Row() && nEndRow == pLastRange->aEnd.Row() )
+ {
+ // keep vertical part of aMMRect, only update horizontal position
+ aMMRect = *pLastMM;
+
+ long nLeft = 0;
+ SCCOL i;
+ for (i=0; i<nStartCol; i++)
+ nLeft += GetColWidth(i,nTab);
+ long nRight = nLeft;
+ for (i=nStartCol; i<=nEndCol; i++)
+ nRight += GetColWidth(i,nTab);
+
+ aMMRect.Left() = (long)(nLeft * HMM_PER_TWIPS);
+ aMMRect.Right() = (long)(nRight * HMM_PER_TWIPS);
+ }
+ else
+ aMMRect = pThis->GetMMRect( nStartCol, nStartRow, nEndCol, nEndRow, nTab );
+
+ if ( pLastRange && pLastMM )
+ {
+ *pLastRange = ScRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
+ *pLastMM = aMMRect;
+ }
+
+ if ( pThis->HasAnyDraw( nTab, aMMRect ))
+ return FALSE;
+
+ if ( nStartCol > 0 && !bLeftIsEmpty )
+ {
+ // aehnlich wie in ScPrintFunc::AdjustPrintArea
+ //! ExtendPrintArea erst ab Start-Spalte des Druckbereichs
+
+ SCCOL nExtendCol = nStartCol - 1;
+ SCROW nTmpRow = nEndRow;
+
+ pThis->ExtendMerge( 0,nStartRow, nExtendCol,nTmpRow, nTab,
+ FALSE, TRUE ); // kein Refresh, incl. Attrs
+
+ OutputDevice* pDev = pThis->GetPrinter();
+ pDev->SetMapMode( MAP_PIXEL ); // wichtig fuer GetNeededSize
+ pThis->ExtendPrintArea( pDev, nTab, 0, nStartRow, nExtendCol, nEndRow );
+ if ( nExtendCol >= nStartCol )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void ScDocument::Clear( sal_Bool bFromDestructor )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ {
+ delete pTab[i];
+ pTab[i]=NULL;
+ }
+ delete pSelectionAttr;
+ pSelectionAttr = NULL;
+
+ if (pDrawLayer)
+ {
+ // #116168#
+ //pDrawLayer->Clear();
+ pDrawLayer->ClearModel( bFromDestructor );
+ }
+}
+
+BOOL ScDocument::HasControl( SCTAB nTab, const Rectangle& rMMRect )
+{
+ BOOL bFound = FALSE;
+
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ if (pObject->ISA(SdrUnoObj))
+ {
+ Rectangle aObjRect = pObject->GetLogicRect();
+ if ( aObjRect.IsOver( rMMRect ) )
+ bFound = TRUE;
+ }
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+
+ return bFound;
+}
+
+void ScDocument::InvalidateControls( Window* pWin, SCTAB nTab, const Rectangle& rMMRect )
+{
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if (pObject->ISA(SdrUnoObj))
+ {
+ Rectangle aObjRect = pObject->GetLogicRect();
+ if ( aObjRect.IsOver( rMMRect ) )
+ {
+ // Uno-Controls zeichnen sich immer komplett, ohne Ruecksicht
+ // auf ClippingRegions. Darum muss das ganze Objekt neu gepainted
+ // werden, damit die Selektion auf der Tabelle nicht uebermalt wird.
+
+ //pWin->Invalidate( aObjRect.GetIntersection( rMMRect ) );
+ pWin->Invalidate( aObjRect );
+ }
+ }
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+}
+
+BOOL ScDocument::HasDetectiveObjects(SCTAB nTab) const
+{
+ // looks for detective objects, annotations don't count
+ // (used to adjust scale so detective objects hit their cells better)
+
+ BOOL bFound = FALSE;
+
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ // anything on the internal layer except captions (annotations)
+ if ( (pObject->GetLayer() == SC_LAYER_INTERN) && !ScDrawLayer::IsNoteCaption( pObject ) )
+ bFound = TRUE;
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+
+ return bFound;
+}
+
+void ScDocument::UpdateFontCharSet()
+{
+ // In alten Versionen (bis incl. 4.0 ohne SP) wurden beim Austausch zwischen
+ // Systemen die CharSets in den Font-Attributen nicht angepasst.
+ // Das muss fuer Dokumente bis incl SP2 nun nachgeholt werden:
+ // Alles, was nicht SYMBOL ist, wird auf den System-CharSet umgesetzt.
+ // Bei neuen Dokumenten (Version SC_FONTCHARSET) sollte der CharSet stimmen.
+
+ BOOL bUpdateOld = ( nSrcVer < SC_FONTCHARSET );
+
+ CharSet eSysSet = gsl_getSystemTextEncoding();
+ if ( eSrcSet != eSysSet || bUpdateOld )
+ {
+ USHORT nCount,i;
+ SvxFontItem* pItem;
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+ nCount = pPool->GetItemCount(ATTR_FONT);
+ for (i=0; i<nCount; i++)
+ {
+ pItem = (SvxFontItem*)pPool->GetItem(ATTR_FONT, i);
+ if ( pItem && ( pItem->GetCharSet() == eSrcSet ||
+ ( bUpdateOld && pItem->GetCharSet() != RTL_TEXTENCODING_SYMBOL ) ) )
+ pItem->GetCharSet() = eSysSet;
+ }
+
+ if ( pDrawLayer )
+ {
+ SfxItemPool& rDrawPool = pDrawLayer->GetItemPool();
+ nCount = rDrawPool.GetItemCount(EE_CHAR_FONTINFO);
+ for (i=0; i<nCount; i++)
+ {
+ pItem = (SvxFontItem*)rDrawPool.GetItem(EE_CHAR_FONTINFO, i);
+ if ( pItem && ( pItem->GetCharSet() == eSrcSet ||
+ ( bUpdateOld && pItem->GetCharSet() != RTL_TEXTENCODING_SYMBOL ) ) )
+ pItem->GetCharSet() = eSysSet;
+ }
+ }
+ }
+}
+
+void ScDocument::SetImportingXML( BOOL bVal )
+{
+ bImportingXML = bVal;
+ if (pDrawLayer)
+ pDrawLayer->EnableAdjust(!bImportingXML);
+
+ if ( !bVal )
+ {
+ // #i57869# after loading, do the real RTL mirroring for the sheets that have the LoadingRTL flag set
+
+ for ( SCTAB nTab=0; nTab<=MAXTAB && pTab[nTab]; nTab++ )
+ if ( pTab[nTab]->IsLoadingRTL() )
+ {
+ pTab[nTab]->SetLoadingRTL( FALSE );
+ SetLayoutRTL( nTab, TRUE ); // includes mirroring; bImportingXML must be cleared first
+ }
+ }
+}
+
+void ScDocument::SetXMLFromWrapper( BOOL bVal )
+{
+ bXMLFromWrapper = bVal;
+}
+
+vos::ORef<SvxForbiddenCharactersTable> ScDocument::GetForbiddenCharacters()
+{
+ return xForbiddenCharacters;
+}
+
+void ScDocument::SetForbiddenCharacters( const vos::ORef<SvxForbiddenCharactersTable> xNew )
+{
+ xForbiddenCharacters = xNew;
+ if ( pEditEngine )
+ pEditEngine->SetForbiddenCharsTable( xForbiddenCharacters );
+ if ( pDrawLayer )
+ pDrawLayer->SetForbiddenCharsTable( xForbiddenCharacters );
+}
+
+BOOL ScDocument::IsValidAsianCompression() const
+{
+ return ( nAsianCompression != SC_ASIANCOMPRESSION_INVALID );
+}
+
+BYTE ScDocument::GetAsianCompression() const
+{
+ if ( nAsianCompression == SC_ASIANCOMPRESSION_INVALID )
+ return 0;
+ else
+ return nAsianCompression;
+}
+
+void ScDocument::SetAsianCompression(BYTE nNew)
+{
+ nAsianCompression = nNew;
+ if ( pEditEngine )
+ pEditEngine->SetAsianCompressionMode( nAsianCompression );
+ if ( pDrawLayer )
+ pDrawLayer->SetCharCompressType( nAsianCompression );
+}
+
+BOOL ScDocument::IsValidAsianKerning() const
+{
+ return ( nAsianKerning != SC_ASIANKERNING_INVALID );
+}
+
+BOOL ScDocument::GetAsianKerning() const
+{
+ if ( nAsianKerning == SC_ASIANKERNING_INVALID )
+ return FALSE;
+ else
+ return (BOOL)nAsianKerning;
+}
+
+void ScDocument::SetAsianKerning(BOOL bNew)
+{
+ nAsianKerning = (BYTE)bNew;
+ if ( pEditEngine )
+ pEditEngine->SetKernAsianPunctuation( (BOOL)nAsianKerning );
+ if ( pDrawLayer )
+ pDrawLayer->SetKernAsianPunctuation( (BOOL)nAsianKerning );
+}
+
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
new file mode 100644
index 000000000000..c58e054fb62a
--- /dev/null
+++ b/sc/source/core/data/document.cxx
@@ -0,0 +1,4471 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: document.cxx,v $
+ * $Revision: 1.90.36.8 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#define _ZFORLIST_DECLARE_TABLE
+#include "scitems.hxx"
+#include <svx/eeitem.hxx>
+
+#include <svx/boxitem.hxx>
+#include <svx/frmdiritem.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/editeng.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdocapt.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/objsh.hxx>
+#include <svtools/poolcach.hxx>
+#include <svtools/saveopt.hxx>
+#include <svtools/zforlist.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <tools/tenccvt.hxx>
+
+#include <com/sun/star/text/WritingMode2.hpp>
+
+#include "document.hxx"
+#include "table.hxx"
+#include "attrib.hxx"
+#include "attarray.hxx"
+#include "markarr.hxx"
+#include "patattr.hxx"
+#include "rangenam.hxx"
+#include "poolhelp.hxx"
+#include "docpool.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "globstr.hrc"
+#include "rechead.hxx"
+#include "dbcolect.hxx"
+#include "pivot.hxx"
+#include "chartlis.hxx"
+#include "rangelst.hxx"
+#include "markdata.hxx"
+#include "drwlayer.hxx"
+#include "conditio.hxx"
+#include "validat.hxx"
+#include "prnsave.hxx"
+#include "chgtrack.hxx"
+#include "sc.hrc"
+#include "scresid.hxx"
+#include "hints.hxx"
+#include "detdata.hxx"
+#include "cell.hxx"
+#include "dpobject.hxx"
+#include "indexmap.hxx"
+#include "detfunc.hxx" // for UpdateAllComments
+#include "scmod.hxx"
+#include "dociter.hxx"
+#include "progress.hxx"
+#include "autonamecache.hxx"
+#include "bcaslot.hxx"
+#include "postit.hxx"
+#include "externalrefmgr.hxx"
+
+namespace WritingMode2 = ::com::sun::star::text::WritingMode2;
+
+struct ScDefaultAttr
+{
+ const ScPatternAttr* pAttr;
+ SCROW nFirst;
+ SCSIZE nCount;
+ ScDefaultAttr(const ScPatternAttr* pPatAttr) : pAttr(pPatAttr), nFirst(0), nCount(0) {}
+};
+
+struct ScLessDefaultAttr
+{
+ sal_Bool operator() (const ScDefaultAttr& rValue1, const ScDefaultAttr& rValue2) const
+ {
+ return rValue1.pAttr < rValue2.pAttr;
+ }
+};
+
+typedef std::set<ScDefaultAttr, ScLessDefaultAttr> ScDefaultAttrSet;
+
+void ScDocument::MakeTable( SCTAB nTab )
+{
+ if ( ValidTab(nTab) && !pTab[nTab] )
+ {
+ String aString = ScGlobal::GetRscString(STR_TABLE_DEF); //"Tabelle"
+ aString += String::CreateFromInt32(nTab+1);
+ CreateValidTabName( aString ); // keine doppelten
+
+ pTab[nTab] = new ScTable(this, nTab, aString);
+ ++nMaxTableNumber;
+ }
+}
+
+
+BOOL ScDocument::HasTable( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return TRUE;
+
+ return FALSE;
+}
+
+
+BOOL ScDocument::GetName( SCTAB nTab, String& rName ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ {
+ pTab[nTab]->GetName( rName );
+ return TRUE;
+ }
+ rName.Erase();
+ return FALSE;
+}
+
+
+BOOL ScDocument::GetTable( const String& rName, SCTAB& rTab ) const
+{
+ String aUpperName = rName;
+ ScGlobal::pCharClass->toUpper(aUpperName);
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ {
+ if ( pTab[i]->GetUpperName() == aUpperName )
+ {
+ rTab = i;
+ return TRUE;
+ }
+ }
+ rTab = 0;
+ return FALSE;
+}
+
+
+BOOL ScDocument::ValidTabName( const String& rName ) const
+{
+ xub_StrLen nLen = rName.Len();
+ if (!nLen)
+ return false;
+
+#if 1
+ // Restrict sheet names to what Excel accepts.
+ /* TODO: We may want to remove this restriction for full ODFF compliance.
+ * Merely loading and calculating ODF documents using these characters in
+ * sheet names is not affected by this, but all sheet name editing and
+ * copying functionality is, maybe falling back to "Sheet4" or similar. */
+ for (xub_StrLen i = 0; i < nLen; ++i)
+ {
+ const sal_Unicode c = rName.GetChar(i);
+ switch (c)
+ {
+ case ':':
+ case '\\':
+ case '/':
+ case '?':
+ case '*':
+ case '[':
+ case ']':
+ // these characters are not allowed to match XL's convention.
+ return false;
+ case '\'':
+ if (i == 0 || i == nLen - 1)
+ // single quote is not allowed at the first or last
+ // character position.
+ return false;
+ break;
+ }
+ }
+#endif
+
+ return true;
+}
+
+
+BOOL ScDocument::ValidNewTabName( const String& rName ) const
+{
+ BOOL bValid = ValidTabName(rName);
+ for (SCTAB i=0; (i<=MAXTAB) && bValid; i++)
+ if (pTab[i])
+ {
+ String aOldName;
+ pTab[i]->GetName(aOldName);
+ bValid = !ScGlobal::pTransliteration->isEqual( rName, aOldName );
+ }
+ return bValid;
+}
+
+
+void ScDocument::CreateValidTabName(String& rName) const
+{
+ if ( !ValidTabName(rName) )
+ {
+ // neu erzeugen
+
+ const String aStrTable( ScResId(SCSTR_TABLE) );
+ BOOL bOk = FALSE;
+
+ // vorneweg testen, ob der Prefix als gueltig erkannt wird
+ // wenn nicht, nur doppelte vermeiden
+ BOOL bPrefix = ValidTabName( aStrTable );
+ DBG_ASSERT(bPrefix, "ungueltiger Tabellenname");
+ SCTAB nDummy;
+
+ SCTAB nLoops = 0; // "zur Sicherheit"
+ for ( SCTAB i = nMaxTableNumber+1; !bOk && nLoops <= MAXTAB; i++ )
+ {
+ rName = aStrTable;
+ rName += String::CreateFromInt32(i);
+ if (bPrefix)
+ bOk = ValidNewTabName( rName );
+ else
+ bOk = !GetTable( rName, nDummy );
+ ++nLoops;
+ }
+
+ DBG_ASSERT(bOk, "kein gueltiger Tabellenname gefunden");
+ if ( !bOk )
+ rName = aStrTable;
+ }
+ else
+ {
+ // uebergebenen Namen ueberpruefen
+
+ if ( !ValidNewTabName(rName) )
+ {
+ SCTAB i = 1;
+ String aName;
+ do
+ {
+ i++;
+ aName = rName;
+ aName += '_';
+ aName += String::CreateFromInt32(static_cast<sal_Int32>(i));
+ }
+ while (!ValidNewTabName(aName) && (i < MAXTAB+1));
+ rName = aName;
+ }
+ }
+}
+
+
+BOOL ScDocument::InsertTab( SCTAB nPos, const String& rName,
+ BOOL bExternalDocument )
+{
+ SCTAB nTabCount = GetTableCount();
+ BOOL bValid = ValidTab(nTabCount);
+ if ( !bExternalDocument ) // sonst rName == "'Doc'!Tab", vorher pruefen
+ bValid = (bValid && ValidNewTabName(rName));
+ if (bValid)
+ {
+ if (nPos == SC_TAB_APPEND || nPos == nTabCount)
+ {
+ pTab[nTabCount] = new ScTable(this, nTabCount, rName);
+ ++nMaxTableNumber;
+ if ( bExternalDocument )
+ pTab[nTabCount]->SetVisible( FALSE );
+ }
+ else
+ {
+ if (VALIDTAB(nPos) && (nPos < nTabCount))
+ {
+ ScRange aRange( 0,0,nPos, MAXCOL,MAXROW,MAXTAB );
+ xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
+ xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,1 );
+ pRangeName->UpdateTabRef( nPos, 1 );
+ pDBCollection->UpdateReference(
+ URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
+#if OLD_PIVOT_IMPLEMENTATION
+ if (pPivotCollection)
+ pPivotCollection->UpdateReference(
+ URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
+#endif
+ if (pDPCollection)
+ pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
+ if (pDetOpList)
+ pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,1 );
+ UpdateChartRef( URM_INSDEL, 0,0,nPos, MAXCOL,MAXROW,MAXTAB, 0,0,1 );
+ UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,1 );
+ if ( pUnoBroadcaster )
+ pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,1 ) );
+
+ SCTAB i;
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateInsertTab(nPos);
+ for (i = nTabCount; i > nPos; i--)
+ pTab[i] = pTab[i - 1];
+ pTab[nPos] = new ScTable(this, nPos, rName);
+ ++nMaxTableNumber;
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateCompile();
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartAllListeners();
+
+ // update conditional formats after table is inserted
+ if ( pCondFormList )
+ pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
+ if ( pValidationList )
+ pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,1 );
+ // #81844# sheet names of references are not valid until sheet is inserted
+ if ( pChartListenerCollection )
+ pChartListenerCollection->UpdateScheduledSeriesRanges();
+
+ // Update cells containing external references.
+ if (pExternalRefMgr.get())
+ pExternalRefMgr->updateRefInsertTable(nPos);
+
+ SetDirty();
+ bValid = TRUE;
+ }
+ else
+ bValid = FALSE;
+ }
+ }
+ return bValid;
+}
+
+
+BOOL ScDocument::DeleteTab( SCTAB nTab, ScDocument* pRefUndoDoc )
+{
+ BOOL bValid = FALSE;
+ if (VALIDTAB(nTab))
+ {
+ if (pTab[nTab])
+ {
+ SCTAB nTabCount = GetTableCount();
+ if (nTabCount > 1)
+ {
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ ScRange aRange( 0, 0, nTab, MAXCOL, MAXROW, nTab );
+ DelBroadcastAreasInRange( aRange );
+
+ // #i8180# remove database ranges etc. that are on the deleted tab
+ // (restored in undo with ScRefUndoData)
+
+ xColNameRanges->DeleteOnTab( nTab );
+ xRowNameRanges->DeleteOnTab( nTab );
+ pDBCollection->DeleteOnTab( nTab );
+ if (pDPCollection)
+ pDPCollection->DeleteOnTab( nTab );
+ if (pDetOpList)
+ pDetOpList->DeleteOnTab( nTab );
+ DeleteAreaLinksOnTab( nTab );
+
+ // normal reference update
+
+ aRange.aEnd.SetTab( MAXTAB );
+ xColNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
+ xRowNameRanges->UpdateReference( URM_INSDEL, this, aRange, 0,0,-1 );
+ pRangeName->UpdateTabRef( nTab, 2 );
+ pDBCollection->UpdateReference(
+ URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
+#if OLD_PIVOT_IMPLEMENTATION
+ if (pPivotCollection)
+ pPivotCollection->UpdateReference(
+ URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
+#endif
+ if (pDPCollection)
+ pDPCollection->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
+ if (pDetOpList)
+ pDetOpList->UpdateReference( this, URM_INSDEL, aRange, 0,0,-1 );
+ UpdateChartRef( URM_INSDEL, 0,0,nTab, MAXCOL,MAXROW,MAXTAB, 0,0,-1 );
+ UpdateRefAreaLinks( URM_INSDEL, aRange, 0,0,-1 );
+ if ( pCondFormList )
+ pCondFormList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
+ if ( pValidationList )
+ pValidationList->UpdateReference( URM_INSDEL, aRange, 0,0,-1 );
+ if ( pUnoBroadcaster )
+ pUnoBroadcaster->Broadcast( ScUpdateRefHint( URM_INSDEL, aRange, 0,0,-1 ) );
+
+ SCTAB i;
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateDeleteTab(nTab,FALSE,
+ pRefUndoDoc ? pRefUndoDoc->pTab[i] : 0);
+ delete pTab[nTab];
+ for (i=nTab + 1; i < nTabCount; i++)
+ pTab[i - 1] = pTab[i];
+ pTab[nTabCount - 1] = NULL;
+ --nMaxTableNumber;
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->UpdateCompile();
+ // Excel-Filter loescht einige Tables waehrend des Ladens,
+ // Listener werden erst nach dem Laden aufgesetzt
+ if ( !bInsertingFromOtherDoc )
+ {
+ for (i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartAllListeners();
+ SetDirty();
+ }
+ // #81844# sheet names of references are not valid until sheet is deleted
+ pChartListenerCollection->UpdateScheduledSeriesRanges();
+
+
+ // Update cells containing external references.
+ if (pExternalRefMgr.get())
+ pExternalRefMgr->updateRefDeleteTable(nTab);
+
+ SetAutoCalc( bOldAutoCalc );
+ bValid = TRUE;
+ }
+ }
+ }
+ return bValid;
+}
+
+
+BOOL ScDocument::RenameTab( SCTAB nTab, const String& rName, BOOL /* bUpdateRef */,
+ BOOL bExternalDocument )
+{
+ BOOL bValid = FALSE;
+ SCTAB i;
+ if VALIDTAB(nTab)
+ if (pTab[nTab])
+ {
+ if ( bExternalDocument )
+ bValid = TRUE; // zusammengesetzter Name
+ else
+ bValid = ValidTabName(rName);
+ for (i=0; (i<=MAXTAB) && bValid; i++)
+ if (pTab[i] && (i != nTab))
+ {
+ String aOldName;
+ pTab[i]->GetName(aOldName);
+ bValid = !ScGlobal::pTransliteration->isEqual( rName, aOldName );
+ }
+ if (bValid)
+ {
+ // #i75258# update charts before renaming, so they can get their live data objects.
+ // Once the charts are live, the sheet can be renamed without problems.
+ if ( pChartListenerCollection )
+ pChartListenerCollection->UpdateChartsContainingTab( nTab );
+ pTab[nTab]->SetName(rName);
+ }
+ }
+ return bValid;
+}
+
+
+void ScDocument::SetVisible( SCTAB nTab, BOOL bVisible )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetVisible(bVisible);
+}
+
+
+BOOL ScDocument::IsVisible( SCTAB nTab ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->IsVisible();
+
+ return FALSE;
+}
+
+
+void ScDocument::SetLayoutRTL( SCTAB nTab, BOOL bRTL )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ if ( bImportingXML )
+ {
+ // #i57869# only set the LoadingRTL flag, the real setting (including mirroring)
+ // is applied in SetImportingXML(FALSE). This is so the shapes can be loaded in
+ // normal LTR mode.
+
+ pTab[nTab]->SetLoadingRTL( bRTL );
+ return;
+ }
+
+ pTab[nTab]->SetLayoutRTL( bRTL ); // only sets the flag
+ pTab[nTab]->SetDrawPageSize();
+
+ // mirror existing objects:
+
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( *pPage, IM_DEEPNOGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ // objects with ScDrawObjData are re-positioned in SetPageSize,
+ // don't mirror again
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( pObject );
+ if ( !pData )
+ pDrawLayer->MirrorRTL( pObject );
+
+ pObject->SetContextWritingMode( bRTL ? WritingMode2::RL_TB : WritingMode2::LR_TB );
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+}
+
+
+BOOL ScDocument::IsLayoutRTL( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->IsLayoutRTL();
+
+ return FALSE;
+}
+
+
+BOOL ScDocument::IsNegativePage( SCTAB nTab ) const
+{
+ // Negative page area is always used for RTL layout.
+ // The separate method is used to find all RTL handling of drawing objects.
+ return IsLayoutRTL( nTab );
+}
+
+
+/* ----------------------------------------------------------------------------
+ benutzten Bereich suchen:
+
+ GetCellArea - nur Daten
+ GetTableArea - Daten / Attribute
+ GetPrintArea - beruecksichtigt auch Zeichenobjekte,
+ streicht Attribute bis ganz rechts / unten
+---------------------------------------------------------------------------- */
+
+
+BOOL ScDocument::GetCellArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->GetCellArea( rEndCol, rEndRow );
+
+ rEndCol = 0;
+ rEndRow = 0;
+ return FALSE;
+}
+
+
+BOOL ScDocument::GetTableArea( SCTAB nTab, SCCOL& rEndCol, SCROW& rEndRow ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->GetTableArea( rEndCol, rEndRow );
+
+ rEndCol = 0;
+ rEndRow = 0;
+ return FALSE;
+}
+
+
+// zusammenhaengender Bereich
+
+void ScDocument::GetDataArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow, BOOL bIncludeOld )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->GetDataArea( rStartCol, rStartRow, rEndCol, rEndRow, bIncludeOld );
+}
+
+
+void ScDocument::LimitChartArea( SCTAB nTab, SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->LimitChartArea( rStartCol, rStartRow, rEndCol, rEndRow );
+}
+
+
+void ScDocument::LimitChartIfAll( ScRangeListRef& rRangeList )
+{
+ ScRangeListRef aNew = new ScRangeList;
+ if (rRangeList.Is())
+ {
+ ULONG nCount = rRangeList->Count();
+ for (ULONG i=0; i<nCount; i++)
+ {
+ ScRange aRange(*rRangeList->GetObject( i ));
+ if ( ( aRange.aStart.Col() == 0 && aRange.aEnd.Col() == MAXCOL ) ||
+ ( aRange.aStart.Row() == 0 && aRange.aEnd.Row() == MAXROW ) )
+ {
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ SCTAB nTab = aRange.aStart.Tab();
+ if (pTab[nTab])
+ pTab[nTab]->LimitChartArea(nStartCol, nStartRow, nEndCol, nEndRow);
+ aRange.aStart.SetCol( nStartCol );
+ aRange.aStart.SetRow( nStartRow );
+ aRange.aEnd.SetCol( nEndCol );
+ aRange.aEnd.SetRow( nEndRow );
+ }
+ aNew->Append(aRange);
+ }
+ }
+ else
+ {
+ DBG_ERROR("LimitChartIfAll: Ref==0");
+ }
+ rRangeList = aNew;
+}
+
+
+BOOL ScDocument::CanInsertRow( const ScRange& rRange ) const
+{
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+ SCSIZE nSize = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
+
+ BOOL bTest = TRUE;
+ for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
+ if (pTab[i])
+ bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
+
+ return bTest;
+}
+
+
+BOOL ScDocument::InsertRow( SCCOL nStartCol, SCTAB nStartTab,
+ SCCOL nEndCol, SCTAB nEndTab,
+ SCROW nStartRow, SCSIZE nSize, ScDocument* pRefUndoDoc )
+{
+ SCTAB i;
+
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartTab, nEndTab );
+
+ BOOL bTest = TRUE;
+ BOOL bRet = FALSE;
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for ( i = nStartTab; i <= nEndTab && bTest; i++)
+ if (pTab[i])
+ bTest &= pTab[i]->TestInsertRow( nStartCol, nEndCol, nSize );
+ if (bTest)
+ {
+ // UpdateBroadcastAreas muss vor UpdateReference gerufen werden, damit nicht
+ // Eintraege verschoben werden, die erst bei UpdateReference neu erzeugt werden
+
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( nStartCol, nStartRow, nStartTab ),
+ ScAddress( nEndCol, MAXROW, nEndTab )), 0, static_cast<SCsROW>(nSize), 0 );
+ UpdateReference( URM_INSDEL, nStartCol, nStartRow, nStartTab,
+ nEndCol, MAXROW, nEndTab,
+ 0, static_cast<SCsROW>(nSize), 0, pRefUndoDoc, FALSE ); // without drawing objects
+ for (i=nStartTab; i<=nEndTab; i++)
+ if (pTab[i])
+ pTab[i]->InsertRow( nStartCol, nEndCol, nStartRow, nSize );
+
+ // #82991# UpdateRef for drawing layer must be after inserting,
+ // when the new row heights are known.
+ for (i=nStartTab; i<=nEndTab; i++)
+ if (pTab[i])
+ pTab[i]->UpdateDrawRef( URM_INSDEL,
+ nStartCol, nStartRow, nStartTab, nEndCol, MAXROW, nEndTab,
+ 0, static_cast<SCsROW>(nSize), 0 );
+
+ if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
+ { // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
+ // ein neues Listening faellig, bisherige Listener wurden in
+ // FormulaCell UpdateReference abgehaengt
+ StartAllListeners();
+ }
+ else
+ { // Listeners have been removed in UpdateReference
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartNeededListeners();
+ // #69592# at least all cells using range names pointing relative
+ // to the moved range must recalculate
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->SetRelNameDirty();
+ }
+ bRet = TRUE;
+ }
+ SetAutoCalc( bOldAutoCalc );
+ if ( bRet )
+ pChartListenerCollection->UpdateDirtyCharts();
+ return bRet;
+}
+
+
+BOOL ScDocument::InsertRow( const ScRange& rRange, ScDocument* pRefUndoDoc )
+{
+ return InsertRow( rRange.aStart.Col(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Tab(),
+ rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
+ pRefUndoDoc );
+}
+
+
+void ScDocument::DeleteRow( SCCOL nStartCol, SCTAB nStartTab,
+ SCCOL nEndCol, SCTAB nEndTab,
+ SCROW nStartRow, SCSIZE nSize,
+ ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
+{
+ SCTAB i;
+
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartTab, nEndTab );
+
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+
+ if ( ValidRow(nStartRow+nSize) )
+ {
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nStartTab ),
+ ScAddress( nEndCol, nStartRow+nSize-1, nEndTab ) ) );
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( nStartCol, nStartRow+nSize, nStartTab ),
+ ScAddress( nEndCol, MAXROW, nEndTab )), 0, -(static_cast<SCsROW>(nSize)), 0 );
+ }
+ else
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nStartTab ),
+ ScAddress( nEndCol, MAXROW, nEndTab ) ) );
+
+ if ( ValidRow(nStartRow+nSize) )
+ {
+ UpdateReference( URM_INSDEL, nStartCol, nStartRow+nSize, nStartTab,
+ nEndCol, MAXROW, nEndTab,
+ 0, -(static_cast<SCsROW>(nSize)), 0, pRefUndoDoc );
+ }
+
+ if (pUndoOutline)
+ *pUndoOutline = FALSE;
+
+ for ( i = nStartTab; i <= nEndTab; i++)
+ if (pTab[i])
+ pTab[i]->DeleteRow( nStartCol, nEndCol, nStartRow, nSize, pUndoOutline );
+
+ if ( ValidRow(nStartRow+nSize) )
+ { // Listeners have been removed in UpdateReference
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartNeededListeners();
+ // #69592# at least all cells using range names pointing relative to
+ // the moved range must recalculate
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->SetRelNameDirty();
+ }
+
+ SetAutoCalc( bOldAutoCalc );
+ pChartListenerCollection->UpdateDirtyCharts();
+}
+
+
+void ScDocument::DeleteRow( const ScRange& rRange, ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
+{
+ DeleteRow( rRange.aStart.Col(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Tab(),
+ rRange.aStart.Row(), static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1),
+ pRefUndoDoc, pUndoOutline );
+}
+
+
+BOOL ScDocument::CanInsertCol( const ScRange& rRange ) const
+{
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+ SCSIZE nSize = static_cast<SCSIZE>(nEndCol - nStartCol + 1);
+
+ BOOL bTest = TRUE;
+ for (SCTAB i=nStartTab; i<=nEndTab && bTest; i++)
+ if (pTab[i])
+ bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
+
+ return bTest;
+}
+
+
+BOOL ScDocument::InsertCol( SCROW nStartRow, SCTAB nStartTab,
+ SCROW nEndRow, SCTAB nEndTab,
+ SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc )
+{
+ SCTAB i;
+
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+
+ BOOL bTest = TRUE;
+ BOOL bRet = FALSE;
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for ( i = nStartTab; i <= nEndTab && bTest; i++)
+ if (pTab[i])
+ bTest &= pTab[i]->TestInsertCol( nStartRow, nEndRow, nSize );
+ if (bTest)
+ {
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( nStartCol, nStartRow, nStartTab ),
+ ScAddress( MAXCOL, nEndRow, nEndTab )), static_cast<SCsCOL>(nSize), 0, 0 );
+ UpdateReference( URM_INSDEL, nStartCol, nStartRow, nStartTab,
+ MAXCOL, nEndRow, nEndTab,
+ static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc );
+ for (i=nStartTab; i<=nEndTab; i++)
+ if (pTab[i])
+ pTab[i]->InsertCol( nStartCol, nStartRow, nEndRow, nSize );
+
+ if ( pChangeTrack && pChangeTrack->IsInDeleteUndo() )
+ { // durch Restaurierung von Referenzen auf geloeschte Bereiche ist
+ // ein neues Listening faellig, bisherige Listener wurden in
+ // FormulaCell UpdateReference abgehaengt
+ StartAllListeners();
+ }
+ else
+ { // Listeners have been removed in UpdateReference
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartNeededListeners();
+ // #69592# at least all cells using range names pointing relative
+ // to the moved range must recalculate
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->SetRelNameDirty();
+ }
+ bRet = TRUE;
+ }
+ SetAutoCalc( bOldAutoCalc );
+ if ( bRet )
+ pChartListenerCollection->UpdateDirtyCharts();
+ return bRet;
+}
+
+
+BOOL ScDocument::InsertCol( const ScRange& rRange, ScDocument* pRefUndoDoc )
+{
+ return InsertCol( rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Row(), rRange.aEnd.Tab(),
+ rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
+ pRefUndoDoc );
+}
+
+
+void ScDocument::DeleteCol(SCROW nStartRow, SCTAB nStartTab, SCROW nEndRow, SCTAB nEndTab,
+ SCCOL nStartCol, SCSIZE nSize, ScDocument* pRefUndoDoc,
+ BOOL* pUndoOutline )
+{
+ SCTAB i;
+
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+
+ if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
+ {
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nStartTab ),
+ ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize-1), nEndRow, nEndTab ) ) );
+ UpdateBroadcastAreas( URM_INSDEL, ScRange(
+ ScAddress( sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nStartTab ),
+ ScAddress( MAXCOL, nEndRow, nEndTab )), -static_cast<SCsCOL>(nSize), 0, 0 );
+ }
+ else
+ DelBroadcastAreasInRange( ScRange(
+ ScAddress( nStartCol, nStartRow, nStartTab ),
+ ScAddress( MAXCOL, nEndRow, nEndTab ) ) );
+
+ if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
+ {
+ UpdateReference( URM_INSDEL, sal::static_int_cast<SCCOL>(nStartCol+nSize), nStartRow, nStartTab,
+ MAXCOL, nEndRow, nEndTab,
+ -static_cast<SCsCOL>(nSize), 0, 0, pRefUndoDoc );
+ }
+
+ if (pUndoOutline)
+ *pUndoOutline = FALSE;
+
+ for ( i = nStartTab; i <= nEndTab; i++)
+ if (pTab[i])
+ pTab[i]->DeleteCol( nStartCol, nStartRow, nEndRow, nSize, pUndoOutline );
+
+ if ( ValidCol(sal::static_int_cast<SCCOL>(nStartCol+nSize)) )
+ { // Listeners have been removed in UpdateReference
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StartNeededListeners();
+ // #69592# at least all cells using range names pointing relative to
+ // the moved range must recalculate
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->SetRelNameDirty();
+ }
+
+ SetAutoCalc( bOldAutoCalc );
+ pChartListenerCollection->UpdateDirtyCharts();
+}
+
+
+void ScDocument::DeleteCol( const ScRange& rRange, ScDocument* pRefUndoDoc, BOOL* pUndoOutline )
+{
+ DeleteCol( rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Row(), rRange.aEnd.Tab(),
+ rRange.aStart.Col(), static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1),
+ pRefUndoDoc, pUndoOutline );
+}
+
+
+// fuer Area-Links: Zellen einuegen/loeschen, wenn sich der Bereich veraendert
+// (ohne Paint)
+
+
+void lcl_GetInsDelRanges( const ScRange& rOld, const ScRange& rNew,
+ ScRange& rColRange, BOOL& rInsCol, BOOL& rDelCol,
+ ScRange& rRowRange, BOOL& rInsRow, BOOL& rDelRow )
+{
+ DBG_ASSERT( rOld.aStart == rNew.aStart, "FitBlock: Anfang unterschiedlich" );
+
+ rInsCol = rDelCol = rInsRow = rDelRow = FALSE;
+
+ SCCOL nStartX = rOld.aStart.Col();
+ SCROW nStartY = rOld.aStart.Row();
+ SCCOL nOldEndX = rOld.aEnd.Col();
+ SCROW nOldEndY = rOld.aEnd.Row();
+ SCCOL nNewEndX = rNew.aEnd.Col();
+ SCROW nNewEndY = rNew.aEnd.Row();
+ SCTAB nTab = rOld.aStart.Tab();
+
+ // wenn es mehr Zeilen werden, werden Spalten auf der alten Hoehe eingefuegt/geloescht
+ BOOL bGrowY = ( nNewEndY > nOldEndY );
+ SCROW nColEndY = bGrowY ? nOldEndY : nNewEndY;
+ SCCOL nRowEndX = bGrowY ? nNewEndX : nOldEndX;
+
+ // Spalten
+
+ if ( nNewEndX > nOldEndX ) // Spalten einfuegen
+ {
+ rColRange = ScRange( nOldEndX+1, nStartY, nTab, nNewEndX, nColEndY, nTab );
+ rInsCol = TRUE;
+ }
+ else if ( nNewEndX < nOldEndX ) // Spalten loeschen
+ {
+ rColRange = ScRange( nNewEndX+1, nStartY, nTab, nOldEndX, nColEndY, nTab );
+ rDelCol = TRUE;
+ }
+
+ // Zeilen
+
+ if ( nNewEndY > nOldEndY ) // Zeilen einfuegen
+ {
+ rRowRange = ScRange( nStartX, nOldEndY+1, nTab, nRowEndX, nNewEndY, nTab );
+ rInsRow = TRUE;
+ }
+ else if ( nNewEndY < nOldEndY ) // Zeilen loeschen
+ {
+ rRowRange = ScRange( nStartX, nNewEndY+1, nTab, nRowEndX, nOldEndY, nTab );
+ rDelRow = TRUE;
+ }
+}
+
+
+BOOL ScDocument::HasPartOfMerged( const ScRange& rRange )
+{
+ BOOL bPart = FALSE;
+ SCTAB nTab = rRange.aStart.Tab();
+
+ SCCOL nStartX = rRange.aStart.Col();
+ SCROW nStartY = rRange.aStart.Row();
+ SCCOL nEndX = rRange.aEnd.Col();
+ SCROW nEndY = rRange.aEnd.Row();
+
+ if (HasAttrib( nStartX, nStartY, nTab, nEndX, nEndY, nTab,
+ HASATTR_MERGED | HASATTR_OVERLAPPED ))
+ {
+ ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
+ ExtendOverlapped( nStartX, nStartY, nEndX, nEndY, nTab );
+
+ bPart = ( nStartX != rRange.aStart.Col() || nEndX != rRange.aEnd.Col() ||
+ nStartY != rRange.aStart.Row() || nEndY != rRange.aEnd.Row() );
+ }
+ return bPart;
+}
+
+
+BOOL ScDocument::CanFitBlock( const ScRange& rOld, const ScRange& rNew )
+{
+ if ( rOld == rNew )
+ return TRUE;
+
+ BOOL bOk = TRUE;
+ BOOL bInsCol,bDelCol,bInsRow,bDelRow;
+ ScRange aColRange,aRowRange;
+ lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
+
+ if ( bInsCol && !CanInsertCol( aColRange ) ) // Zellen am Rand ?
+ bOk = FALSE;
+ if ( bInsRow && !CanInsertRow( aRowRange ) ) // Zellen am Rand ?
+ bOk = FALSE;
+
+ if ( bInsCol || bDelCol )
+ {
+ aColRange.aEnd.SetCol(MAXCOL);
+ if ( HasPartOfMerged(aColRange) )
+ bOk = FALSE;
+ }
+ if ( bInsRow || bDelRow )
+ {
+ aRowRange.aEnd.SetRow(MAXROW);
+ if ( HasPartOfMerged(aRowRange) )
+ bOk = FALSE;
+ }
+
+ return bOk;
+}
+
+
+void ScDocument::FitBlock( const ScRange& rOld, const ScRange& rNew, BOOL bClear )
+{
+ if (bClear)
+ DeleteAreaTab( rOld, IDF_ALL );
+
+ BOOL bInsCol,bDelCol,bInsRow,bDelRow;
+ ScRange aColRange,aRowRange;
+ lcl_GetInsDelRanges( rOld, rNew, aColRange,bInsCol,bDelCol, aRowRange,bInsRow,bDelRow );
+
+ if ( bInsCol )
+ InsertCol( aColRange ); // Spalten zuerst einfuegen
+ if ( bInsRow )
+ InsertRow( aRowRange );
+
+ if ( bDelRow )
+ DeleteRow( aRowRange ); // Zeilen zuerst loeschen
+ if ( bDelCol )
+ DeleteCol( aColRange );
+
+ // Referenzen um eingefuegte Zeilen erweitern
+
+ if ( bInsCol || bInsRow )
+ {
+ ScRange aGrowSource = rOld;
+ aGrowSource.aEnd.SetCol(Min( rOld.aEnd.Col(), rNew.aEnd.Col() ));
+ aGrowSource.aEnd.SetRow(Min( rOld.aEnd.Row(), rNew.aEnd.Row() ));
+ SCCOL nGrowX = bInsCol ? ( rNew.aEnd.Col() - rOld.aEnd.Col() ) : 0;
+ SCROW nGrowY = bInsRow ? ( rNew.aEnd.Row() - rOld.aEnd.Row() ) : 0;
+ UpdateGrow( aGrowSource, nGrowX, nGrowY );
+ }
+}
+
+
+void ScDocument::DeleteArea(SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark, USHORT nDelFlag)
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCTAB i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if ( rMark.GetTableSelect(i) || bIsUndo )
+ pTab[i]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::DeleteAreaTab(SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ SCTAB nTab, USHORT nDelFlag)
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ {
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ pTab[nTab]->DeleteArea(nCol1, nRow1, nCol2, nRow2, nDelFlag);
+ SetAutoCalc( bOldAutoCalc );
+ }
+}
+
+
+void ScDocument::DeleteAreaTab( const ScRange& rRange, USHORT nDelFlag )
+{
+ for ( SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); nTab++ )
+ DeleteAreaTab( rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(),
+ nTab, nDelFlag );
+}
+
+
+void ScDocument::InitUndoSelected( ScDocument* pSrcDoc, const ScMarkData& rTabSelection,
+ BOOL bColInfo, BOOL bRowInfo )
+{
+ if (bIsUndo)
+ {
+ Clear();
+
+ xPoolHelper = pSrcDoc->xPoolHelper;
+
+ String aString;
+ for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
+ if ( rTabSelection.GetTableSelect( nTab ) )
+ {
+ pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
+ nMaxTableNumber = nTab + 1;
+ }
+ }
+ else
+ {
+ DBG_ERROR("InitUndo");
+ }
+}
+
+
+void ScDocument::InitUndo( ScDocument* pSrcDoc, SCTAB nTab1, SCTAB nTab2,
+ BOOL bColInfo, BOOL bRowInfo )
+{
+ if (bIsUndo)
+ {
+ Clear();
+
+ xPoolHelper = pSrcDoc->xPoolHelper;
+
+ String aString;
+ for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
+ pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
+
+ nMaxTableNumber = nTab2 + 1;
+ }
+ else
+ {
+ DBG_ERROR("InitUndo");
+ }
+}
+
+
+void ScDocument::AddUndoTab( SCTAB nTab1, SCTAB nTab2, BOOL bColInfo, BOOL bRowInfo )
+{
+ if (bIsUndo)
+ {
+ String aString;
+ for (SCTAB nTab = nTab1; nTab <= nTab2; nTab++)
+ if (!pTab[nTab])
+ pTab[nTab] = new ScTable(this, nTab, aString, bColInfo, bRowInfo);
+
+ if ( nMaxTableNumber <= nTab2 )
+ nMaxTableNumber = nTab2 + 1;
+ }
+ else
+ {
+ DBG_ERROR("InitUndo");
+ }
+}
+
+
+void ScDocument::SetCutMode( BOOL bVal )
+{
+ if (bIsClip)
+ bCutMode = bVal;
+ else
+ {
+ DBG_ERROR("SetCutMode without bIsClip");
+ }
+}
+
+
+BOOL ScDocument::IsCutMode()
+{
+ if (bIsClip)
+ return bCutMode;
+ else
+ {
+ DBG_ERROR("IsCutMode ohne bIsClip");
+ return FALSE;
+ }
+}
+
+
+void ScDocument::CopyToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks, BOOL bColRowFlags )
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ PutInOrder( nTab1, nTab2 );
+ if( !pDestDoc->aDocName.Len() )
+ pDestDoc->aDocName = aDocName;
+ if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
+ {
+ BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCTAB i = nTab1; i <= nTab2; i++)
+ {
+ if (pTab[i] && pDestDoc->pTab[i])
+ pTab[i]->CopyToTable( nCol1, nRow1, nCol2, nRow2, nFlags,
+ bOnlyMarked, pDestDoc->pTab[i], pMarks,
+ FALSE, bColRowFlags );
+ }
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+ }
+}
+
+
+void ScDocument::UndoToDocument(SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks)
+{
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ PutInOrder( nTab1, nTab2 );
+ if (VALIDTAB(nTab1) && VALIDTAB(nTab2))
+ {
+ BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ if (nTab1 > 0)
+ CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, FALSE, pDestDoc, pMarks );
+
+ for (SCTAB i = nTab1; i <= nTab2; i++)
+ {
+ if (pTab[i] && pDestDoc->pTab[i])
+ pTab[i]->UndoToTable(nCol1, nRow1, nCol2, nRow2, nFlags,
+ bOnlyMarked, pDestDoc->pTab[i], pMarks);
+ }
+
+ if (nTab2 < MAXTAB)
+ CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, FALSE, pDestDoc, pMarks );
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+ }
+}
+
+
+void ScDocument::CopyToDocument(const ScRange& rRange,
+ USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks, BOOL bColRowFlags)
+{
+ ScRange aNewRange = rRange;
+ aNewRange.Justify();
+
+ if( !pDestDoc->aDocName.Len() )
+ pDestDoc->aDocName = aDocName;
+ BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCTAB i = aNewRange.aStart.Tab(); i <= aNewRange.aEnd.Tab(); i++)
+ if (pTab[i] && pDestDoc->pTab[i])
+ pTab[i]->CopyToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
+ aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
+ nFlags, bOnlyMarked, pDestDoc->pTab[i],
+ pMarks, FALSE, bColRowFlags);
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::UndoToDocument(const ScRange& rRange,
+ USHORT nFlags, BOOL bOnlyMarked, ScDocument* pDestDoc,
+ const ScMarkData* pMarks)
+{
+ ScRange aNewRange = rRange;
+ aNewRange.Justify();
+ SCTAB nTab1 = aNewRange.aStart.Tab();
+ SCTAB nTab2 = aNewRange.aEnd.Tab();
+
+ BOOL bOldAutoCalc = pDestDoc->GetAutoCalc();
+ pDestDoc->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ if (nTab1 > 0)
+ CopyToDocument( 0,0,0, MAXCOL,MAXROW,nTab1-1, IDF_FORMULA, FALSE, pDestDoc, pMarks );
+
+ for (SCTAB i = nTab1; i <= nTab2; i++)
+ {
+ if (pTab[i] && pDestDoc->pTab[i])
+ pTab[i]->UndoToTable(aNewRange.aStart.Col(), aNewRange.aStart.Row(),
+ aNewRange.aEnd.Col(), aNewRange.aEnd.Row(),
+ nFlags, bOnlyMarked, pDestDoc->pTab[i], pMarks);
+ }
+
+ if (nTab2 < MAXTAB)
+ CopyToDocument( 0,0,nTab2+1, MAXCOL,MAXROW,MAXTAB, IDF_FORMULA, FALSE, pDestDoc, pMarks );
+ pDestDoc->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::CopyToClip(SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ BOOL bCut, ScDocument* pClipDoc,
+ BOOL bAllTabs, const ScMarkData* pMarks,
+ BOOL bKeepScenarioFlags, BOOL bIncludeObjects, BOOL bCloneNoteCaptions)
+{
+ DBG_ASSERT( bAllTabs || pMarks, "CopyToClip: ScMarkData fehlt" );
+
+ if (!bIsClip)
+ {
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ if (!pClipDoc)
+ {
+ DBG_ERROR("CopyToClip: no ClipDoc");
+ pClipDoc = SC_MOD()->GetClipDoc();
+ }
+
+ pClipDoc->aDocName = aDocName;
+ pClipDoc->aClipRange = ScRange( nCol1,nRow1,0, nCol2,nRow2,0 );
+ pClipDoc->ResetClip( this, pMarks );
+ USHORT i;
+ SCTAB j;
+
+ std::set<USHORT> aUsedNames; // indexes of named ranges that are used in the copied cells
+ for (j = 0; j <= MAXTAB; j++)
+ if (pTab[j] && pClipDoc->pTab[j])
+ if ( bAllTabs || !pMarks || pMarks->GetTableSelect(j) )
+ pTab[j]->FindRangeNamesInUse( nCol1, nRow1, nCol2, nRow2, aUsedNames );
+
+ pClipDoc->pRangeName->FreeAll();
+ for (i = 0; i < pRangeName->GetCount(); i++) //! DB-Bereiche Pivot-Bereiche auch !!!
+ {
+ USHORT nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
+ bool bInUse = ( aUsedNames.find(nIndex) != aUsedNames.end() );
+ if (bInUse)
+ {
+ ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
+ if (!pClipDoc->pRangeName->Insert(pData))
+ delete pData;
+ else
+ pData->SetIndex(nIndex);
+ }
+ }
+ for (j = 0; j <= MAXTAB; j++)
+ if (pTab[j] && pClipDoc->pTab[j])
+ if ( bAllTabs || !pMarks || pMarks->GetTableSelect(j) )
+ {
+ pTab[j]->CopyToClip(nCol1, nRow1, nCol2, nRow2, pClipDoc->pTab[j], bKeepScenarioFlags, bCloneNoteCaptions);
+
+ if ( pDrawLayer && bIncludeObjects )
+ {
+ // also copy drawing objects
+
+ Rectangle aObjRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, j );
+ pDrawLayer->CopyToClip( pClipDoc, j, aObjRect );
+ }
+ }
+
+ pClipDoc->bCutMode = bCut;
+ }
+}
+
+
+void ScDocument::CopyTabToClip(SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ SCTAB nTab, ScDocument* pClipDoc)
+{
+ if (!bIsClip)
+ {
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ if (!pClipDoc)
+ {
+ DBG_ERROR("CopyTabToClip: no ClipDoc");
+ pClipDoc = SC_MOD()->GetClipDoc();
+ }
+
+ pClipDoc->aDocName = aDocName;
+ pClipDoc->aClipRange = ScRange( nCol1,nRow1,0, nCol2,nRow2,0 );
+ pClipDoc->ResetClip( this, nTab );
+
+ if (pTab[nTab] && pClipDoc->pTab[nTab])
+ pTab[nTab]->CopyToClip(nCol1, nRow1, nCol2, nRow2, pClipDoc->pTab[nTab], FALSE, TRUE);
+
+ pClipDoc->bCutMode = FALSE;
+ }
+}
+
+
+void ScDocument::TransposeClip( ScDocument* pTransClip, USHORT nFlags, BOOL bAsLink )
+{
+ DBG_ASSERT( bIsClip && pTransClip && pTransClip->bIsClip,
+ "TransposeClip mit falschem Dokument" );
+
+ // initialisieren
+ // -> pTransClip muss vor dem Original-Dokument geloescht werden!
+
+ pTransClip->ResetClip(this, (ScMarkData*)NULL); // alle
+
+ // Bereiche uebernehmen
+
+ pTransClip->pRangeName->FreeAll();
+ for (USHORT i = 0; i < pRangeName->GetCount(); i++) //! DB-Bereiche Pivot-Bereiche auch !!!
+ {
+ USHORT nIndex = ((ScRangeData*)((*pRangeName)[i]))->GetIndex();
+ ScRangeData* pData = new ScRangeData(*((*pRangeName)[i]));
+ if (!pTransClip->pRangeName->Insert(pData))
+ delete pData;
+ else
+ pData->SetIndex(nIndex);
+ }
+
+ // Daten
+
+ if ( ValidRow(aClipRange.aEnd.Row()-aClipRange.aStart.Row()) )
+ {
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ {
+ DBG_ASSERT( pTransClip->pTab[i], "TransposeClip: Tabelle nicht da" );
+ pTab[i]->TransposeClip( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
+ aClipRange.aEnd.Col(), aClipRange.aEnd.Row(),
+ pTransClip->pTab[i], nFlags, bAsLink );
+
+ if ( pDrawLayer && ( nFlags & IDF_OBJECTS ) )
+ {
+ // Drawing objects are copied to the new area without transposing.
+ // CopyFromClip is used to adjust the objects to the transposed block's
+ // cell range area.
+ // (pDrawLayer in the original clipboard document is set only if there
+ // are drawing objects to copy)
+
+ pTransClip->InitDrawLayer();
+ Rectangle aSourceRect = GetMMRect( aClipRange.aStart.Col(), aClipRange.aStart.Row(),
+ aClipRange.aEnd.Col(), aClipRange.aEnd.Row(), i );
+ Rectangle aDestRect = pTransClip->GetMMRect( 0, 0,
+ static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
+ static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()), i );
+ pTransClip->pDrawLayer->CopyFromClip( pDrawLayer, i, aSourceRect, ScAddress(0,0,i), aDestRect );
+ }
+ }
+
+ pTransClip->aClipRange = ScRange( 0, 0, aClipRange.aStart.Tab(),
+ static_cast<SCCOL>(aClipRange.aEnd.Row() - aClipRange.aStart.Row()),
+ static_cast<SCROW>(aClipRange.aEnd.Col() - aClipRange.aStart.Col()),
+ aClipRange.aEnd.Tab() );
+ }
+ else
+ {
+ DBG_ERROR("TransposeClip: zu gross");
+ }
+
+ // Dies passiert erst beim Einfuegen...
+
+ bCutMode = FALSE;
+}
+
+
+BOOL ScDocument::IsClipboardSource() const
+{
+ ScDocument* pClipDoc = SC_MOD()->GetClipDoc();
+ return pClipDoc && pClipDoc->xPoolHelper.isValid() &&
+ xPoolHelper->GetDocPool() == pClipDoc->xPoolHelper->GetDocPool();
+}
+
+
+void ScDocument::StartListeningFromClip( SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark, USHORT nInsFlag )
+{
+ if (nInsFlag & IDF_CONTENTS)
+ {
+ for (SCTAB i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->StartListeningInArea( nCol1, nRow1, nCol2, nRow2 );
+ }
+}
+
+
+void ScDocument::BroadcastFromClip( SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark, USHORT nInsFlag )
+{
+ if (nInsFlag & IDF_CONTENTS)
+ {
+ ScBulkBroadcast aBulkBroadcast( GetBASM());
+ for (SCTAB i = 0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->BroadcastInArea( nCol1, nRow1, nCol2, nRow2 );
+ }
+}
+
+
+void ScDocument::CopyBlockFromClip( SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark,
+ SCsCOL nDx, SCsROW nDy,
+ const ScCopyBlockFromClipParams* pCBFCP )
+{
+ ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
+ SCTAB nTabEnd = pCBFCP->nTabEnd;
+ SCTAB nClipTab = 0;
+ for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
+ {
+ if (pTab[i] && rMark.GetTableSelect(i) )
+ {
+ while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
+
+ pTab[i]->CopyFromClip( nCol1, nRow1, nCol2, nRow2, nDx, nDy,
+ pCBFCP->nInsFlag, pCBFCP->bAsLink, pCBFCP->bSkipAttrForEmpty, ppClipTab[nClipTab] );
+
+ if ( pCBFCP->pClipDoc->pDrawLayer && ( pCBFCP->nInsFlag & IDF_OBJECTS ) )
+ {
+ // also copy drawing objects
+
+ // drawing layer must be created before calling CopyFromClip
+ // (ScDocShell::MakeDrawLayer also does InitItems etc.)
+ DBG_ASSERT( pDrawLayer, "CopyBlockFromClip: No drawing layer" );
+ if ( pDrawLayer )
+ {
+ // For GetMMRect, the row heights in the target document must already be valid
+ // (copied in an extra step before pasting, or updated after pasting cells, but
+ // before pasting objects).
+
+ Rectangle aSourceRect = pCBFCP->pClipDoc->GetMMRect(
+ nCol1-nDx, nRow1-nDy, nCol2-nDx, nRow2-nDy, nClipTab );
+ Rectangle aDestRect = GetMMRect( nCol1, nRow1, nCol2, nRow2, i );
+ pDrawLayer->CopyFromClip( pCBFCP->pClipDoc->pDrawLayer, nClipTab, aSourceRect,
+ ScAddress( nCol1, nRow1, i ), aDestRect );
+ }
+ }
+
+ nClipTab = (nClipTab+1) % (MAXTAB+1);
+ }
+ }
+ if ( pCBFCP->nInsFlag & IDF_CONTENTS )
+ {
+ nClipTab = 0;
+ for (SCTAB i = pCBFCP->nTabStart; i <= nTabEnd; i++)
+ {
+ if (pTab[i] && rMark.GetTableSelect(i) )
+ {
+ while (!ppClipTab[nClipTab]) nClipTab = (nClipTab+1) % (MAXTAB+1);
+ SCsTAB nDz = ((SCsTAB)i) - nClipTab;
+
+ // #89081# ranges of consecutive selected tables (in clipboard and dest. doc)
+ // must be handled in one UpdateReference call
+ SCTAB nFollow = 0;
+ while ( i + nFollow < nTabEnd
+ && rMark.GetTableSelect( i + nFollow + 1 )
+ && nClipTab + nFollow < MAXTAB
+ && ppClipTab[nClipTab + nFollow + 1] )
+ ++nFollow;
+
+ if ( pCBFCP->pClipDoc->bCutMode )
+ {
+ BOOL bOldInserting = IsInsertingFromOtherDoc();
+ SetInsertingFromOtherDoc( TRUE);
+ UpdateReference( URM_MOVE,
+ nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
+ nDx, nDy, nDz, pCBFCP->pRefUndoDoc );
+ SetInsertingFromOtherDoc( bOldInserting);
+ }
+ else
+ UpdateReference( URM_COPY,
+ nCol1, nRow1, i, nCol2, nRow2, i+nFollow,
+ nDx, nDy, nDz, pCBFCP->pRefUndoDoc, FALSE );
+
+ nClipTab = (nClipTab+nFollow+1) % (MAXTAB+1);
+ i = sal::static_int_cast<SCTAB>( i + nFollow );
+ }
+ }
+ }
+}
+
+
+void ScDocument::CopyNonFilteredFromClip( SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rMark,
+ SCsCOL nDx, SCsROW /* nDy */,
+ const ScCopyBlockFromClipParams* pCBFCP,
+ SCROW & rClipStartRow )
+{
+ // call CopyBlockFromClip for ranges of consecutive non-filtered rows
+ // nCol1/nRow1 etc. is in target doc
+
+ // filtered state is taken from first used table in clipboard (as in GetClipArea)
+ SCTAB nFlagTab = 0;
+ ScTable** ppClipTab = pCBFCP->pClipDoc->pTab;
+ while ( nFlagTab < MAXTAB && !ppClipTab[nFlagTab] )
+ ++nFlagTab;
+
+ const ScBitMaskCompressedArray< SCROW, BYTE> & rSourceFlags =
+ pCBFCP->pClipDoc->GetRowFlagsArray( nFlagTab);
+
+ SCROW nSourceRow = rClipStartRow;
+ SCROW nSourceEnd = pCBFCP->pClipDoc->aClipRange.aEnd.Row();
+ SCROW nDestRow = nRow1;
+
+ while ( nSourceRow <= nSourceEnd && nDestRow <= nRow2 )
+ {
+ // skip filtered rows
+ nSourceRow = rSourceFlags.GetFirstForCondition( nSourceRow, nSourceEnd, CR_FILTERED, 0);
+
+ if ( nSourceRow <= nSourceEnd )
+ {
+ // look for more non-filtered rows following
+ SCROW nFollow = rSourceFlags.GetBitStateEnd( nSourceRow, CR_FILTERED, 0) - nSourceRow;
+ if (nFollow > nSourceEnd - nSourceRow)
+ nFollow = nSourceEnd - nSourceRow;
+ if (nFollow > nRow2 - nDestRow)
+ nFollow = nRow2 - nDestRow;
+
+ SCsROW nNewDy = ((SCsROW)nDestRow) - nSourceRow;
+ CopyBlockFromClip( nCol1, nDestRow, nCol2, nDestRow + nFollow, rMark, nDx, nNewDy, pCBFCP );
+
+ nSourceRow += nFollow + 1;
+ nDestRow += nFollow + 1;
+ }
+ }
+ rClipStartRow = nSourceRow;
+}
+
+
+void ScDocument::CopyFromClip( const ScRange& rDestRange, const ScMarkData& rMark,
+ USHORT nInsFlag,
+ ScDocument* pRefUndoDoc, ScDocument* pClipDoc, BOOL bResetCut,
+ BOOL bAsLink, BOOL bIncludeFiltered, BOOL bSkipAttrForEmpty,
+ const ScRangeList * pDestRanges )
+{
+ if (!bIsClip)
+ {
+ if (!pClipDoc)
+ {
+ DBG_ERROR("CopyFromClip: no ClipDoc");
+ pClipDoc = SC_MOD()->GetClipDoc();
+ }
+ if (pClipDoc->bIsClip && pClipDoc->GetTableCount())
+ {
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // avoid multiple recalculations
+
+ SvNumberFormatter* pThisFormatter = xPoolHelper->GetFormTable();
+ SvNumberFormatter* pOtherFormatter = pClipDoc->xPoolHelper->GetFormTable();
+ if (pOtherFormatter && pOtherFormatter != pThisFormatter)
+ {
+ SvNumberFormatterIndexTable* pExchangeList =
+ pThisFormatter->MergeFormatter(*(pOtherFormatter));
+ if (pExchangeList->Count() > 0)
+ pFormatExchangeList = pExchangeList;
+ }
+
+ USHORT nClipRangeNames = pClipDoc->pRangeName->GetCount();
+ // array containing range names which might need update of indices
+ ScRangeData** pClipRangeNames = nClipRangeNames ? new ScRangeData* [nClipRangeNames] : NULL;
+ // the index mapping thereof
+ ScIndexMap aClipRangeMap( nClipRangeNames );
+ BOOL bRangeNameReplace = FALSE;
+
+ for (USHORT i = 0; i < nClipRangeNames; i++) //! DB-Bereiche Pivot-Bereiche auch
+ {
+ /* Copy only if the name doesn't exist in this document.
+ If it exists we use the already existing name instead,
+ another possibility could be to create new names if
+ documents differ.
+ A proper solution would ask the user how to proceed.
+ The adjustment of the indices in the formulas is done later.
+ */
+ ScRangeData* pClipRangeData = (*pClipDoc->pRangeName)[i];
+ USHORT k;
+ if ( pRangeName->SearchName( pClipRangeData->GetName(), k ) )
+ {
+ pClipRangeNames[i] = NULL; // range name not inserted
+ USHORT nOldIndex = pClipRangeData->GetIndex();
+ USHORT nNewIndex = ((*pRangeName)[k])->GetIndex();
+ aClipRangeMap.SetPair( i, nOldIndex, nNewIndex );
+ if ( !bRangeNameReplace )
+ bRangeNameReplace = ( nOldIndex != nNewIndex );
+ }
+ else
+ {
+ ScRangeData* pData = new ScRangeData( *pClipRangeData );
+ pData->SetDocument(this);
+ if ( pRangeName->FindIndex( pData->GetIndex() ) )
+ pData->SetIndex(0); // need new index, done in Insert
+ if ( pRangeName->Insert( pData ) )
+ {
+ pClipRangeNames[i] = pData;
+ USHORT nOldIndex = pClipRangeData->GetIndex();
+ USHORT nNewIndex = pData->GetIndex();
+ aClipRangeMap.SetPair( i, nOldIndex, nNewIndex );
+ if ( !bRangeNameReplace )
+ bRangeNameReplace = ( nOldIndex != nNewIndex );
+ }
+ else
+ { // must be an overflow
+ delete pData;
+ pClipRangeNames[i] = NULL;
+ aClipRangeMap.SetPair( i, pClipRangeData->GetIndex(), 0 );
+ bRangeNameReplace = TRUE;
+ }
+ }
+ }
+ SCCOL nAllCol1 = rDestRange.aStart.Col();
+ SCROW nAllRow1 = rDestRange.aStart.Row();
+ SCCOL nAllCol2 = rDestRange.aEnd.Col();
+ SCROW nAllRow2 = rDestRange.aEnd.Row();
+
+ SCCOL nXw = 0;
+ SCROW nYw = 0;
+ for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++) // find largest merge overlap
+ if (pClipDoc->pTab[nTab]) // all sheets of the clipboard content
+ {
+ SCCOL nThisEndX = pClipDoc->aClipRange.aEnd.Col();
+ SCROW nThisEndY = pClipDoc->aClipRange.aEnd.Row();
+ pClipDoc->ExtendMerge( pClipDoc->aClipRange.aStart.Col(),
+ pClipDoc->aClipRange.aStart.Row(),
+ nThisEndX, nThisEndY, nTab );
+ // only extra value from ExtendMerge
+ nThisEndX = sal::static_int_cast<SCCOL>( nThisEndX - pClipDoc->aClipRange.aEnd.Col() );
+ nThisEndY = sal::static_int_cast<SCROW>( nThisEndY - pClipDoc->aClipRange.aEnd.Row() );
+ if ( nThisEndX > nXw )
+ nXw = nThisEndX;
+ if ( nThisEndY > nYw )
+ nYw = nThisEndY;
+ }
+
+ SCCOL nDestAddX;
+ SCROW nDestAddY;
+ pClipDoc->GetClipArea( nDestAddX, nDestAddY, bIncludeFiltered );
+ nXw = sal::static_int_cast<SCCOL>( nXw + nDestAddX );
+ nYw = sal::static_int_cast<SCROW>( nYw + nDestAddY ); // ClipArea, plus ExtendMerge value
+
+ // Inhalte entweder komplett oder gar nicht loeschen:
+ USHORT nDelFlag = IDF_NONE;
+ if ( nInsFlag & IDF_CONTENTS )
+ nDelFlag |= IDF_CONTENTS;
+ // With bSkipAttrForEmpty, don't remove attributes, copy
+ // on top of existing attributes instead.
+ if ( ( nInsFlag & IDF_ATTRIB ) && !bSkipAttrForEmpty )
+ nDelFlag |= IDF_ATTRIB;
+
+ ScCopyBlockFromClipParams aCBFCP;
+ aCBFCP.pRefUndoDoc = pRefUndoDoc;
+ aCBFCP.pClipDoc = pClipDoc;
+ aCBFCP.nInsFlag = nInsFlag;
+ aCBFCP.bAsLink = bAsLink;
+ aCBFCP.bSkipAttrForEmpty = bSkipAttrForEmpty;
+ aCBFCP.nTabStart = MAXTAB; // wird in der Schleife angepasst
+ aCBFCP.nTabEnd = 0; // wird in der Schleife angepasst
+
+ // Inc/DecRecalcLevel einmal aussen, damit nicht fuer jeden Block
+ // die Draw-Seitengroesse neu berechnet werden muss
+ //! nur wenn ganze Zeilen/Spalten kopiert werden?
+
+ for (SCTAB j = 0; j <= MAXTAB; j++)
+ if (pTab[j] && rMark.GetTableSelect(j))
+ {
+ if ( j < aCBFCP.nTabStart )
+ aCBFCP.nTabStart = j;
+ aCBFCP.nTabEnd = j;
+ pTab[j]->IncRecalcLevel();
+ }
+
+ ScRangeList aLocalRangeList;
+ if (!pDestRanges)
+ {
+ aLocalRangeList.Append( rDestRange);
+ pDestRanges = &aLocalRangeList;
+ }
+
+ bInsertingFromOtherDoc = TRUE; // kein Broadcast/Listener aufbauen bei Insert
+
+ // bei mindestens 64 Zeilen wird in ScColumn::CopyFromClip voralloziert
+ BOOL bDoDouble = ( nYw < 64 && nAllRow2 - nAllRow1 > 64);
+ BOOL bOldDouble = ScColumn::bDoubleAlloc;
+ if (bDoDouble)
+ ScColumn::bDoubleAlloc = TRUE;
+
+ SCCOL nClipStartCol = pClipDoc->aClipRange.aStart.Col();
+ SCROW nClipStartRow = pClipDoc->aClipRange.aStart.Row();
+ // WaE: commented because unused: SCCOL nClipEndCol = pClipDoc->aClipRange.aEnd.Col();
+ SCROW nClipEndRow = pClipDoc->aClipRange.aEnd.Row();
+ for (ULONG nRange = 0; nRange < pDestRanges->Count(); ++nRange)
+ {
+ const ScRange* pRange = pDestRanges->GetObject( nRange);
+ SCCOL nCol1 = pRange->aStart.Col();
+ SCROW nRow1 = pRange->aStart.Row();
+ SCCOL nCol2 = pRange->aEnd.Col();
+ SCROW nRow2 = pRange->aEnd.Row();
+
+ DeleteArea(nCol1, nRow1, nCol2, nRow2, rMark, nDelFlag);
+
+ SCCOL nC1 = nCol1;
+ SCROW nR1 = nRow1;
+ SCCOL nC2 = nC1 + nXw;
+ if (nC2 > nCol2)
+ nC2 = nCol2;
+ SCROW nR2 = nR1 + nYw;
+ if (nR2 > nRow2)
+ nR2 = nRow2;
+
+ do
+ {
+ // Pasting is done column-wise, when pasting to a filtered
+ // area this results in partitioning and we have to
+ // remember and reset the start row for each column until
+ // it can be advanced for the next chunk of unfiltered
+ // rows.
+ SCROW nSaveClipStartRow = nClipStartRow;
+ do
+ {
+ nClipStartRow = nSaveClipStartRow;
+ SCsCOL nDx = ((SCsCOL)nC1) - nClipStartCol;
+ SCsROW nDy = ((SCsROW)nR1) - nClipStartRow;
+ if ( bIncludeFiltered )
+ {
+ CopyBlockFromClip( nC1, nR1, nC2, nR2, rMark, nDx,
+ nDy, &aCBFCP );
+ nClipStartRow += nR2 - nR1 + 1;
+ }
+ else
+ {
+ CopyNonFilteredFromClip( nC1, nR1, nC2, nR2, rMark,
+ nDx, nDy, &aCBFCP, nClipStartRow );
+ }
+ // Not needed for columns, but if it was this would be how to.
+ //if (nClipStartCol > nClipEndCol)
+ // nClipStartCol = pClipDoc->aClipRange.aStart.Col();
+ nC1 = nC2 + 1;
+ nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
+ } while (nC1 <= nCol2);
+ if (nClipStartRow > nClipEndRow)
+ nClipStartRow = pClipDoc->aClipRange.aStart.Row();
+ nC1 = nCol1;
+ nC2 = nC1 + nXw;
+ if (nC2 > nCol2)
+ nC2 = nCol2;
+ nR1 = nR2 + 1;
+ nR2 = Min((SCROW)(nR1 + nYw), nRow2);
+ } while (nR1 <= nRow2);
+ }
+
+ ScColumn::bDoubleAlloc = bOldDouble;
+
+ for (SCTAB k = 0; k <= MAXTAB; k++)
+ if (pTab[k] && rMark.GetTableSelect(k))
+ pTab[k]->DecRecalcLevel();
+
+ bInsertingFromOtherDoc = FALSE;
+ pFormatExchangeList = NULL;
+ if ( bRangeNameReplace )
+ {
+ // first update all inserted named formulas if they contain other
+ // range names and used indices changed
+ for (USHORT i = 0; i < nClipRangeNames; i++) //! DB-Bereiche Pivot-Bereiche auch
+ {
+ if ( pClipRangeNames[i] )
+ pClipRangeNames[i]->ReplaceRangeNamesInUse( aClipRangeMap );
+ }
+ // then update the formulas, they might need the just updated range names
+ for (ULONG nRange = 0; nRange < pDestRanges->Count(); ++nRange)
+ {
+ const ScRange* pRange = pDestRanges->GetObject( nRange);
+ SCCOL nCol1 = pRange->aStart.Col();
+ SCROW nRow1 = pRange->aStart.Row();
+ SCCOL nCol2 = pRange->aEnd.Col();
+ SCROW nRow2 = pRange->aEnd.Row();
+
+ SCCOL nC1 = nCol1;
+ SCROW nR1 = nRow1;
+ SCCOL nC2 = nC1 + nXw;
+ if (nC2 > nCol2)
+ nC2 = nCol2;
+ SCROW nR2 = nR1 + nYw;
+ if (nR2 > nRow2)
+ nR2 = nRow2;
+ do
+ {
+ do
+ {
+ for (SCTAB k = 0; k <= MAXTAB; k++)
+ {
+ if ( pTab[k] && rMark.GetTableSelect(k) )
+ pTab[k]->ReplaceRangeNamesInUse(nC1, nR1,
+ nC2, nR2, aClipRangeMap );
+ }
+ nC1 = nC2 + 1;
+ nC2 = Min((SCCOL)(nC1 + nXw), nCol2);
+ } while (nC1 <= nCol2);
+ nC1 = nCol1;
+ nC2 = nC1 + nXw;
+ if (nC2 > nCol2)
+ nC2 = nCol2;
+ nR1 = nR2 + 1;
+ nR2 = Min((SCROW)(nR1 + nYw), nRow2);
+ } while (nR1 <= nRow2);
+ }
+ }
+ if ( pClipRangeNames )
+ delete [] pClipRangeNames;
+ // Listener aufbauen nachdem alles inserted wurde
+ StartListeningFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
+ // nachdem alle Listener aufgebaut wurden, kann gebroadcastet werden
+ BroadcastFromClip( nAllCol1, nAllRow1, nAllCol2, nAllRow2, rMark, nInsFlag );
+ if (bResetCut)
+ pClipDoc->bCutMode = FALSE;
+ SetAutoCalc( bOldAutoCalc );
+ }
+ }
+}
+
+
+void ScDocument::SetClipArea( const ScRange& rArea, BOOL bCut )
+{
+ if (bIsClip)
+ {
+ aClipRange = rArea;
+ bCutMode = bCut;
+ }
+ else
+ {
+ DBG_ERROR("SetClipArea: kein Clip");
+ }
+}
+
+
+void ScDocument::GetClipArea(SCCOL& nClipX, SCROW& nClipY, BOOL bIncludeFiltered)
+{
+ if (bIsClip)
+ {
+ nClipX = aClipRange.aEnd.Col() - aClipRange.aStart.Col();
+
+ if ( bIncludeFiltered )
+ nClipY = aClipRange.aEnd.Row() - aClipRange.aStart.Row();
+ else
+ {
+ // count non-filtered rows
+ // count on first used table in clipboard
+ SCTAB nCountTab = 0;
+ while ( nCountTab < MAXTAB && !pTab[nCountTab] )
+ ++nCountTab;
+
+ SCROW nResult = GetRowFlagsArray( nCountTab).CountForCondition(
+ aClipRange.aStart.Row(), aClipRange.aEnd.Row(),
+ CR_FILTERED, 0);
+
+ if ( nResult > 0 )
+ nClipY = nResult - 1;
+ else
+ nClipY = 0; // always return at least 1 row
+ }
+ }
+ else
+ {
+ DBG_ERROR("GetClipArea: kein Clip");
+ }
+}
+
+
+void ScDocument::GetClipStart(SCCOL& nClipX, SCROW& nClipY)
+{
+ if (bIsClip)
+ {
+ nClipX = aClipRange.aStart.Col();
+ nClipY = aClipRange.aStart.Row();
+ }
+ else
+ {
+ DBG_ERROR("GetClipStart: kein Clip");
+ }
+}
+
+
+BOOL ScDocument::HasClipFilteredRows()
+{
+ // count on first used table in clipboard
+ SCTAB nCountTab = 0;
+ while ( nCountTab < MAXTAB && !pTab[nCountTab] )
+ ++nCountTab;
+
+ return GetRowFlagsArray( nCountTab).HasCondition( aClipRange.aStart.Row(),
+ aClipRange.aEnd.Row(), CR_FILTERED, CR_FILTERED);
+}
+
+
+void ScDocument::MixDocument( const ScRange& rRange, USHORT nFunction, BOOL bSkipEmpty,
+ ScDocument* pSrcDoc )
+{
+ SCTAB nTab1 = rRange.aStart.Tab();
+ SCTAB nTab2 = rRange.aEnd.Tab();
+ for (SCTAB i = nTab1; i <= nTab2; i++)
+ if (pTab[i] && pSrcDoc->pTab[i])
+ pTab[i]->MixData( rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(),
+ nFunction, bSkipEmpty, pSrcDoc->pTab[i] );
+}
+
+
+void ScDocument::FillTab( const ScRange& rSrcArea, const ScMarkData& rMark,
+ USHORT nFlags, USHORT nFunction,
+ BOOL bSkipEmpty, BOOL bAsLink )
+{
+ USHORT nDelFlags = nFlags;
+ if (nDelFlags & IDF_CONTENTS)
+ nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
+
+ SCTAB nSrcTab = rSrcArea.aStart.Tab();
+
+ if (ValidTab(nSrcTab) && pTab[nSrcTab])
+ {
+ SCCOL nStartCol = rSrcArea.aStart.Col();
+ SCROW nStartRow = rSrcArea.aStart.Row();
+ SCCOL nEndCol = rSrcArea.aEnd.Col();
+ SCROW nEndRow = rSrcArea.aEnd.Row();
+ ScDocument* pMixDoc = NULL;
+ BOOL bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
+
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+
+ SCTAB nCount = GetTableCount();
+ for (SCTAB i=0; i<nCount; i++)
+ if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
+ {
+ if (bDoMix)
+ {
+ if (!pMixDoc)
+ {
+ pMixDoc = new ScDocument( SCDOCMODE_UNDO );
+ pMixDoc->InitUndo( this, i, i );
+ }
+ else
+ pMixDoc->AddUndoTab( i, i );
+ pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
+ IDF_CONTENTS, FALSE, pMixDoc->pTab[i] );
+ }
+ pTab[i]->DeleteArea( nStartCol,nStartRow, nEndCol,nEndRow, nDelFlags);
+ pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
+ nFlags, FALSE, pTab[i], NULL, bAsLink );
+
+ if (bDoMix)
+ pTab[i]->MixData( nStartCol,nStartRow, nEndCol,nEndRow,
+ nFunction, bSkipEmpty, pMixDoc->pTab[i] );
+ }
+
+ delete pMixDoc;
+
+ SetAutoCalc( bOldAutoCalc );
+ }
+ else
+ {
+ DBG_ERROR("falsche Tabelle");
+ }
+}
+
+
+void ScDocument::FillTabMarked( SCTAB nSrcTab, const ScMarkData& rMark,
+ USHORT nFlags, USHORT nFunction,
+ BOOL bSkipEmpty, BOOL bAsLink )
+{
+ USHORT nDelFlags = nFlags;
+ if (nDelFlags & IDF_CONTENTS)
+ nDelFlags |= IDF_CONTENTS; // immer alle Inhalte oder keine loeschen!
+
+ if (ValidTab(nSrcTab) && pTab[nSrcTab])
+ {
+ ScDocument* pMixDoc = NULL;
+ BOOL bDoMix = ( bSkipEmpty || nFunction ) && ( nFlags & IDF_CONTENTS );
+
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+
+ ScRange aArea;
+ rMark.GetMultiMarkArea( aArea );
+ SCCOL nStartCol = aArea.aStart.Col();
+ SCROW nStartRow = aArea.aStart.Row();
+ SCCOL nEndCol = aArea.aEnd.Col();
+ SCROW nEndRow = aArea.aEnd.Row();
+
+ SCTAB nCount = GetTableCount();
+ for (SCTAB i=0; i<nCount; i++)
+ if ( i!=nSrcTab && pTab[i] && rMark.GetTableSelect(i) )
+ {
+ if (bDoMix)
+ {
+ if (!pMixDoc)
+ {
+ pMixDoc = new ScDocument( SCDOCMODE_UNDO );
+ pMixDoc->InitUndo( this, i, i );
+ }
+ else
+ pMixDoc->AddUndoTab( i, i );
+ pTab[i]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
+ IDF_CONTENTS, TRUE, pMixDoc->pTab[i], &rMark );
+ }
+
+ pTab[i]->DeleteSelection( nDelFlags, rMark );
+ pTab[nSrcTab]->CopyToTable( nStartCol,nStartRow, nEndCol,nEndRow,
+ nFlags, TRUE, pTab[i], &rMark, bAsLink );
+
+ if (bDoMix)
+ pTab[i]->MixMarked( rMark, nFunction, bSkipEmpty, pMixDoc->pTab[i] );
+ }
+
+ delete pMixDoc;
+
+ SetAutoCalc( bOldAutoCalc );
+ }
+ else
+ {
+ DBG_ERROR("falsche Tabelle");
+ }
+}
+
+
+void ScDocument::PutCell( SCCOL nCol, SCROW nRow, SCTAB nTab, ScBaseCell* pCell, BOOL bForceTab )
+{
+ if (VALIDTAB(nTab))
+ {
+ if ( bForceTab && !pTab[nTab] )
+ {
+ BOOL bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
+
+ pTab[nTab] = new ScTable(this, nTab,
+ String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
+ bExtras, bExtras);
+ ++nMaxTableNumber;
+ }
+
+ if (pTab[nTab])
+ pTab[nTab]->PutCell( nCol, nRow, pCell );
+ }
+}
+
+
+void ScDocument::PutCell( const ScAddress& rPos, ScBaseCell* pCell, BOOL bForceTab )
+{
+ SCTAB nTab = rPos.Tab();
+ if ( bForceTab && !pTab[nTab] )
+ {
+ BOOL bExtras = !bIsUndo; // Spaltenbreiten, Zeilenhoehen, Flags
+
+ pTab[nTab] = new ScTable(this, nTab,
+ String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("temp")),
+ bExtras, bExtras);
+ ++nMaxTableNumber;
+ }
+
+ if (pTab[nTab])
+ pTab[nTab]->PutCell( rPos, pCell );
+}
+
+
+BOOL ScDocument::SetString( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rString )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->SetString( nCol, nRow, nTab, rString );
+ else
+ return FALSE;
+}
+
+
+void ScDocument::SetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rVal )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetValue( nCol, nRow, rVal );
+}
+
+
+void ScDocument::GetString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ pTab[nTab]->GetString( nCol, nRow, rString );
+ else
+ rString.Erase();
+}
+
+
+void ScDocument::GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString )
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ pTab[nTab]->GetInputString( nCol, nRow, rString );
+ else
+ rString.Erase();
+}
+
+
+void ScDocument::GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue )
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ rValue = pTab[nTab]->GetValue( nCol, nRow );
+ else
+ rValue = 0.0;
+}
+
+
+double ScDocument::GetValue( const ScAddress& rPos )
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ return pTab[nTab]->GetValue( rPos );
+ return 0.0;
+}
+
+
+void ScDocument::GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ sal_uInt32& rFormat )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ {
+ rFormat = pTab[nTab]->GetNumberFormat( nCol, nRow );
+ return ;
+ }
+ rFormat = 0;
+}
+
+
+sal_uInt32 ScDocument::GetNumberFormat( const ScAddress& rPos ) const
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ return pTab[nTab]->GetNumberFormat( rPos );
+ return 0;
+}
+
+
+void ScDocument::GetNumberFormatInfo( short& nType, ULONG& nIndex,
+ const ScAddress& rPos, const ScBaseCell* pCell ) const
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ {
+ nIndex = pTab[nTab]->GetNumberFormat( rPos );
+ if ( (nIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell &&
+ pCell->GetCellType() == CELLTYPE_FORMULA )
+ static_cast<const ScFormulaCell*>(pCell)->GetFormatInfo( nType, nIndex );
+ else
+ nType = GetFormatTable()->GetType( nIndex );
+ }
+ else
+ {
+ nType = NUMBERFORMAT_UNDEFINED;
+ nIndex = 0;
+ }
+}
+
+
+void ScDocument::GetFormula( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rFormula,
+ BOOL bAsciiExport ) const
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ pTab[nTab]->GetFormula( nCol, nRow, rFormula, bAsciiExport );
+ else
+ rFormula.Erase();
+}
+
+
+CellType ScDocument::GetCellType( const ScAddress& rPos ) const
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ return pTab[nTab]->GetCellType( rPos );
+ return CELLTYPE_NONE;
+}
+
+
+void ScDocument::GetCellType( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ CellType& rCellType ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ rCellType = pTab[nTab]->GetCellType( nCol, nRow );
+ else
+ rCellType = CELLTYPE_NONE;
+}
+
+
+void ScDocument::GetCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ ScBaseCell*& rpCell ) const
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ rpCell = pTab[nTab]->GetCell( nCol, nRow );
+ else
+ {
+ DBG_ERROR("GetCell ohne Tabelle");
+ rpCell = NULL;
+ }
+}
+
+
+ScBaseCell* ScDocument::GetCell( const ScAddress& rPos ) const
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ return pTab[nTab]->GetCell( rPos );
+
+ DBG_ERROR("GetCell ohne Tabelle");
+ return NULL;
+}
+
+
+BOOL ScDocument::HasStringData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ return pTab[nTab]->HasStringData( nCol, nRow );
+ else
+ return FALSE;
+}
+
+
+BOOL ScDocument::HasValueData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ return pTab[nTab]->HasValueData( nCol, nRow );
+ else
+ return FALSE;
+}
+
+
+BOOL ScDocument::HasStringCells( const ScRange& rRange ) const
+{
+ // TRUE, wenn String- oder Editzellen im Bereich
+
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+
+ for ( SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++ )
+ if ( pTab[nTab] && pTab[nTab]->HasStringCells( nStartCol, nStartRow, nEndCol, nEndRow ) )
+ return TRUE;
+
+ return FALSE;
+}
+
+
+BOOL ScDocument::HasSelectionData( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ sal_uInt32 nValidation = static_cast< const SfxUInt32Item* >( GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA ) )->GetValue();
+ if( nValidation )
+ {
+ const ScValidationData* pData = GetValidationEntry( nValidation );
+ if( pData && pData->HasSelectionList() )
+ return TRUE;
+ }
+ return HasStringCells( ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ) );
+}
+
+
+ScPostIt* ScDocument::GetNote( const ScAddress& rPos )
+{
+ ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
+ return pTable ? pTable->GetNote( rPos.Col(), rPos.Row() ) : 0;
+}
+
+
+void ScDocument::TakeNote( const ScAddress& rPos, ScPostIt*& rpNote )
+{
+ if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
+ pTab[ rPos.Tab() ]->TakeNote( rPos.Col(), rPos.Row(), rpNote );
+ else
+ DELETEZ( rpNote );
+}
+
+
+ScPostIt* ScDocument::ReleaseNote( const ScAddress& rPos )
+{
+ ScTable* pTable = ValidTab( rPos.Tab() ) ? pTab[ rPos.Tab() ] : 0;
+ return pTable ? pTable->ReleaseNote( rPos.Col(), rPos.Row() ) : 0;
+}
+
+
+ScPostIt* ScDocument::GetOrCreateNote( const ScAddress& rPos )
+{
+ ScPostIt* pNote = GetNote( rPos );
+ if( !pNote )
+ {
+ pNote = new ScPostIt( *this, rPos, false );
+ TakeNote( rPos, pNote );
+ }
+ return pNote;
+}
+
+
+void ScDocument::DeleteNote( const ScAddress& rPos )
+{
+ if( ValidTab( rPos.Tab() ) && pTab[ rPos.Tab() ] )
+ pTab[ rPos.Tab() ]->DeleteNote( rPos.Col(), rPos.Row() );
+}
+
+
+void ScDocument::SetDirty()
+{
+ BOOL bOldAutoCalc = GetAutoCalc();
+ bAutoCalc = FALSE; // keine Mehrfachberechnung
+ { // scope for bulk broadcast
+ ScBulkBroadcast aBulkBroadcast( GetBASM());
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->SetDirty();
+ }
+
+ // Charts werden zwar auch ohne AutoCalc im Tracking auf Dirty gesetzt,
+ // wenn alle Formeln dirty sind, werden die Charts aber nicht mehr erwischt
+ // (#45205#) - darum alle Charts nochmal explizit
+ if (pChartListenerCollection)
+ pChartListenerCollection->SetDirty();
+
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::SetDirty( const ScRange& rRange )
+{
+ BOOL bOldAutoCalc = GetAutoCalc();
+ bAutoCalc = FALSE; // keine Mehrfachberechnung
+ { // scope for bulk broadcast
+ ScBulkBroadcast aBulkBroadcast( GetBASM());
+ SCTAB nTab2 = rRange.aEnd.Tab();
+ for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
+ if (pTab[i]) pTab[i]->SetDirty( rRange );
+ }
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::SetTableOpDirty( const ScRange& rRange )
+{
+ BOOL bOldAutoCalc = GetAutoCalc();
+ bAutoCalc = FALSE; // no multiple recalculation
+ SCTAB nTab2 = rRange.aEnd.Tab();
+ for (SCTAB i=rRange.aStart.Tab(); i<=nTab2; i++)
+ if (pTab[i]) pTab[i]->SetTableOpDirty( rRange );
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::AddTableOpFormulaCell( ScFormulaCell* pCell )
+{
+ ScInterpreterTableOpParams* p = aTableOpList.Last();
+ if ( p && p->bCollectNotifications )
+ {
+ if ( p->bRefresh )
+ { // refresh pointers only
+ p->aNotifiedFormulaCells.push_back( pCell );
+ }
+ else
+ { // init both, address and pointer
+ p->aNotifiedFormulaCells.push_back( pCell );
+ p->aNotifiedFormulaPos.push_back( pCell->aPos );
+ }
+ }
+}
+
+
+void ScDocument::CalcAll()
+{
+ ClearLookupCaches(); // Ensure we don't deliver zombie data.
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( TRUE );
+ SCTAB i;
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->SetDirtyVar();
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->CalcAll();
+ ClearFormulaTree();
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::CompileAll()
+{
+ if ( pCondFormList )
+ pCondFormList->CompileAll();
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->CompileAll();
+ SetDirty();
+}
+
+
+void ScDocument::CompileXML()
+{
+ BOOL bOldAutoCalc = GetAutoCalc();
+ SetAutoCalc( FALSE );
+ ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(
+ STR_PROGRESS_CALCULATING ), GetXMLImportedFormulaCount() );
+
+ // #b6355215# set AutoNameCache to speed up automatic name lookup
+ DBG_ASSERT( !pAutoNameCache, "AutoNameCache already set" );
+ pAutoNameCache = new ScAutoNameCache( this );
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->CompileXML( aProgress );
+
+ DELETEZ( pAutoNameCache ); // valid only during CompileXML, where cell contents don't change
+
+ if ( pCondFormList )
+ pCondFormList->CompileXML();
+ if ( pValidationList )
+ pValidationList->CompileXML();
+
+ SetDirty();
+ SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScDocument::CalcAfterLoad()
+{
+ SCTAB i;
+
+ if (bIsClip) // Excel-Dateien werden aus dem Clipboard in ein Clip-Doc geladen
+ return; // dann wird erst beim Einfuegen in das richtige Doc berechnet
+
+ bCalcingAfterLoad = TRUE;
+ for ( i = 0; i <= MAXTAB; i++)
+ if (pTab[i]) pTab[i]->CalcAfterLoad();
+ for (i=0; i<=MAXTAB; i++)
+ if (pTab[i]) pTab[i]->SetDirtyAfterLoad();
+ bCalcingAfterLoad = FALSE;
+
+ SetDetectiveDirty(FALSE); // noch keine wirklichen Aenderungen
+}
+
+
+USHORT ScDocument::GetErrCode( const ScAddress& rPos ) const
+{
+ SCTAB nTab = rPos.Tab();
+ if ( pTab[nTab] )
+ return pTab[nTab]->GetErrCode( rPos );
+ return 0;
+}
+
+
+void ScDocument::ResetChanged( const ScRange& rRange )
+{
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ if (pTab[nTab])
+ pTab[nTab]->ResetChanged( rRange );
+}
+
+//
+// Spaltenbreiten / Zeilenhoehen --------------------------------------
+//
+
+
+void ScDocument::SetColWidth( SCCOL nCol, SCTAB nTab, USHORT nNewWidth )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetColWidth( nCol, nNewWidth );
+}
+
+
+void ScDocument::SetRowHeight( SCROW nRow, SCTAB nTab, USHORT nNewHeight )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowHeight( nRow, nNewHeight );
+}
+
+
+void ScDocument::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, USHORT nNewHeight )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowHeightRange
+ ( nStartRow, nEndRow, nNewHeight, 1.0, 1.0 );
+}
+
+
+void ScDocument::SetManualHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, BOOL bManual )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetManualHeight( nStartRow, nEndRow, bManual );
+}
+
+
+USHORT ScDocument::GetColWidth( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetColWidth( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+USHORT ScDocument::GetOriginalWidth( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetOriginalWidth( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+USHORT ScDocument::GetCommonWidth( SCCOL nEndCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetCommonWidth( nEndCol );
+ DBG_ERROR("Wrong table number");
+ return 0;
+}
+
+
+USHORT ScDocument::GetOriginalHeight( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetOriginalHeight( nRow );
+ DBG_ERROR("Wrong table number");
+ return 0;
+}
+
+
+USHORT ScDocument::GetRowHeight( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowHeight( nRow );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+ULONG ScDocument::GetRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
+{
+ if (nStartRow == nEndRow)
+ return GetRowHeight( nStartRow, nTab); // faster for a single row
+
+ // check bounds because this method replaces former for(i=start;i<=end;++i) loops
+ if (nStartRow > nEndRow)
+ return 0;
+
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowHeight( nStartRow, nEndRow);
+
+ DBG_ERROR("wrong sheet number");
+ return 0;
+}
+
+ULONG ScDocument::FastGetRowHeight( SCROW nStartRow, SCROW nEndRow,
+ SCTAB nTab ) const
+{
+ return pTab[nTab]->pRowFlags->SumCoupledArrayForCondition( nStartRow,
+ nEndRow, CR_HIDDEN, 0, *(pTab[nTab]->pRowHeight));
+}
+
+ULONG ScDocument::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow,
+ SCTAB nTab, double fScale ) const
+{
+ // faster for a single row
+ if (nStartRow == nEndRow)
+ return (ULONG) (GetRowHeight( nStartRow, nTab) * fScale);
+
+ // check bounds because this method replaces former for(i=start;i<=end;++i) loops
+ if (nStartRow > nEndRow)
+ return 0;
+
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetScaledRowHeight( nStartRow, nEndRow, fScale);
+
+ DBG_ERROR("wrong sheet number");
+ return 0;
+}
+
+
+const ScSummableCompressedArray< SCROW, USHORT> & ScDocument::GetRowHeightArray(
+ SCTAB nTab ) const
+{
+ const ScSummableCompressedArray< SCROW, USHORT> * pHeight;
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pHeight = pTab[nTab]->GetRowHeightArray();
+ else
+ {
+ DBG_ERROR("wrong sheet number");
+ pHeight = 0;
+ }
+ if (!pHeight)
+ {
+ DBG_ERROR("no row heights at sheet");
+ static ScSummableCompressedArray< SCROW, USHORT> aDummy( MAXROW,
+ ScGlobal::nStdRowHeight);
+ pHeight = &aDummy;
+ }
+ return *pHeight;
+}
+
+
+SCROW ScDocument::GetHiddenRowCount( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetHiddenRowCount( nRow );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+ULONG ScDocument::GetColOffset( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetColOffset( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+ULONG ScDocument::GetRowOffset( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowOffset( nRow );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+USHORT ScDocument::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bFormula, const ScMarkData* pMarkData,
+ BOOL bSimpleTextImport )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetOptimalColWidth( nCol, pDev, nPPTX, nPPTY,
+ rZoomX, rZoomY, bFormula, pMarkData, bSimpleTextImport );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+long ScDocument::GetNeededSize( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bWidth, BOOL bTotalSize )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetNeededSize
+ ( nCol, nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, bTotalSize );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+
+BOOL ScDocument::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, USHORT nExtra,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bShrink )
+{
+//! MarkToMulti();
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->SetOptimalHeight( nStartRow, nEndRow, nExtra,
+ pDev, nPPTX, nPPTY, rZoomX, rZoomY, bShrink );
+ DBG_ERROR("Falsche Tabellennummer");
+ return FALSE;
+}
+
+
+void ScDocument::UpdateAllRowHeights( OutputDevice* pDev, double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY )
+{
+ // one progress across all sheets
+ ScProgress aProgress( GetDocumentShell(), ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), GetWeightedCount() );
+
+ ULONG nProgressStart = 0;
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] )
+ {
+ pTab[nTab]->SetOptimalHeight( 0, MAXROW, 0,
+ pDev, nPPTX, nPPTY, rZoomX, rZoomY, FALSE, &aProgress, nProgressStart );
+ nProgressStart += pTab[nTab]->GetWeightedCount();
+ }
+}
+
+
+//
+// Spalten-/Zeilen-Flags ----------------------------------------------
+//
+
+void ScDocument::ShowCol(SCCOL nCol, SCTAB nTab, BOOL bShow)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ShowCol( nCol, bShow );
+}
+
+
+void ScDocument::ShowRow(SCROW nRow, SCTAB nTab, BOOL bShow)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ShowRow( nRow, bShow );
+}
+
+
+void ScDocument::ShowRows(SCROW nRow1, SCROW nRow2, SCTAB nTab, BOOL bShow)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ShowRows( nRow1, nRow2, bShow );
+}
+
+
+void ScDocument::SetColFlags( SCCOL nCol, SCTAB nTab, BYTE nNewFlags )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetColFlags( nCol, nNewFlags );
+}
+
+
+void ScDocument::SetRowFlags( SCROW nRow, SCTAB nTab, BYTE nNewFlags )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowFlags( nRow, nNewFlags );
+}
+
+
+void ScDocument::SetRowFlags( SCROW nStartRow, SCROW nEndRow, SCTAB nTab, BYTE nNewFlags )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRowFlags( nStartRow, nEndRow, nNewFlags );
+}
+
+
+BYTE ScDocument::GetColFlags( SCCOL nCol, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetColFlags( nCol );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+BYTE ScDocument::GetRowFlags( SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetRowFlags( nRow );
+ DBG_ERROR("Falsche Tabellennummer");
+ return 0;
+}
+
+ScBitMaskCompressedArray< SCROW, BYTE> & ScDocument::GetRowFlagsArrayModifiable(
+ SCTAB nTab )
+{
+ return const_cast< ScBitMaskCompressedArray< SCROW, BYTE> & >(
+ GetRowFlagsArray( nTab));
+}
+
+const ScBitMaskCompressedArray< SCROW, BYTE> & ScDocument::GetRowFlagsArray(
+ SCTAB nTab ) const
+{
+ const ScBitMaskCompressedArray< SCROW, BYTE> * pFlags;
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pFlags = pTab[nTab]->GetRowFlagsArray();
+ else
+ {
+ DBG_ERROR("wrong sheet number");
+ pFlags = 0;
+ }
+ if (!pFlags)
+ {
+ DBG_ERROR("no row flags at sheet");
+ static ScBitMaskCompressedArray< SCROW, BYTE> aDummy( MAXROW, 0);
+ pFlags = &aDummy;
+ }
+ return *pFlags;
+}
+
+
+SCROW ScDocument::GetLastFlaggedRow( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetLastFlaggedRow();
+ return 0;
+}
+
+
+SCCOL ScDocument::GetLastChangedCol( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetLastChangedCol();
+ return 0;
+}
+
+SCROW ScDocument::GetLastChangedRow( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetLastChangedRow();
+ return 0;
+}
+
+
+SCCOL ScDocument::GetNextDifferentChangedCol( SCTAB nTab, SCCOL nStart) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ BYTE nStartFlags = pTab[nTab]->GetColFlags(nStart);
+ USHORT nStartWidth = pTab[nTab]->GetOriginalWidth(nStart);
+ for (SCCOL nCol = nStart + 1; nCol <= MAXCOL; nCol++)
+ {
+ if (((nStartFlags & CR_MANUALBREAK) != (pTab[nTab]->GetColFlags(nCol) & CR_MANUALBREAK)) ||
+ (nStartWidth != pTab[nTab]->GetOriginalWidth(nCol)) ||
+ ((nStartFlags & CR_HIDDEN) != (pTab[nTab]->GetColFlags(nCol) & CR_HIDDEN)) )
+ return nCol;
+ }
+ return MAXCOL+1;
+ }
+ return 0;
+}
+
+SCROW ScDocument::GetNextDifferentChangedRow( SCTAB nTab, SCROW nStart, bool bCareManualSize) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] && pTab[nTab]->GetRowFlagsArray() && pTab[nTab]->GetRowHeightArray() )
+ {
+ BYTE nStartFlags = pTab[nTab]->GetRowFlags(nStart);
+ USHORT nStartHeight = pTab[nTab]->GetOriginalHeight(nStart);
+ for (SCROW nRow = nStart + 1; nRow <= MAXROW; nRow++)
+ {
+ size_t nIndex; // ignored
+ SCROW nFlagsEndRow;
+ SCROW nHeightEndRow;
+ BYTE nFlags = pTab[nTab]->GetRowFlagsArray()->GetValue( nRow, nIndex, nFlagsEndRow );
+ USHORT nHeight = pTab[nTab]->GetRowHeightArray()->GetValue( nRow, nIndex, nHeightEndRow );
+ if (((nStartFlags & CR_MANUALBREAK) != (nFlags & CR_MANUALBREAK)) ||
+ ((nStartFlags & CR_MANUALSIZE) != (nFlags & CR_MANUALSIZE)) ||
+ (bCareManualSize && (nStartFlags & CR_MANUALSIZE) && (nStartHeight != nHeight)) ||
+ (!bCareManualSize && ((nStartHeight != nHeight))))
+ return nRow;
+
+ nRow = std::min( nFlagsEndRow, nHeightEndRow );
+ }
+ return MAXROW+1;
+ }
+ return 0;
+}
+
+BOOL ScDocument::GetColDefault( SCTAB nTab, SCCOL nCol, SCROW nLastRow, SCROW& nDefault)
+{
+ BOOL bRet(FALSE);
+ nDefault = 0;
+ ScDocAttrIterator aDocAttrItr(this, nTab, nCol, 0, nCol, nLastRow);
+ SCCOL nColumn;
+ SCROW nStartRow;
+ SCROW nEndRow;
+ const ScPatternAttr* pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
+ if (nEndRow < nLastRow)
+ {
+ ScDefaultAttrSet aSet;
+ ScDefaultAttrSet::iterator aItr = aSet.end();
+ while (pAttr)
+ {
+ ScDefaultAttr aAttr(pAttr);
+ aItr = aSet.find(aAttr);
+ if (aItr == aSet.end())
+ {
+ aAttr.nCount = static_cast<SCSIZE>(nEndRow - nStartRow + 1);
+ aAttr.nFirst = nStartRow;
+ aSet.insert(aAttr);
+ }
+ else
+ {
+ aAttr.nCount = aItr->nCount + static_cast<SCSIZE>(nEndRow - nStartRow + 1);
+ aAttr.nFirst = aItr->nFirst;
+ aSet.erase(aItr);
+ aSet.insert(aAttr);
+ }
+ pAttr = aDocAttrItr.GetNext(nColumn, nStartRow, nEndRow);
+ }
+ ScDefaultAttrSet::iterator aDefaultItr = aSet.begin();
+ aItr = aDefaultItr;
+ aItr++;
+ while (aItr != aSet.end())
+ {
+ // for entries with equal count, use the one with the lowest start row,
+ // don't use the random order of pointer comparisons
+ if ( aItr->nCount > aDefaultItr->nCount ||
+ ( aItr->nCount == aDefaultItr->nCount && aItr->nFirst < aDefaultItr->nFirst ) )
+ aDefaultItr = aItr;
+ aItr++;
+ }
+ nDefault = aDefaultItr->nFirst;
+ bRet = TRUE;
+ }
+ else
+ bRet = TRUE;
+ return bRet;
+}
+
+BOOL ScDocument::GetRowDefault( SCTAB /* nTab */, SCROW /* nRow */, SCCOL /* nLastCol */, SCCOL& /* nDefault */ )
+{
+ BOOL bRet(FALSE);
+ return bRet;
+}
+
+void ScDocument::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->StripHidden( rX1, rY1, rX2, rY2 );
+}
+
+
+void ScDocument::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2, SCTAB nTab )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ExtendHidden( rX1, rY1, rX2, rY2 );
+}
+
+//
+// Attribute ----------------------------------------------------------
+//
+
+const SfxPoolItem* ScDocument::GetAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, USHORT nWhich ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ {
+ const SfxPoolItem* pTemp = pTab[nTab]->GetAttr( nCol, nRow, nWhich );
+ if (pTemp)
+ return pTemp;
+ else
+ {
+ DBG_ERROR( "Attribut Null" );
+ }
+ }
+ return &xPoolHelper->GetDocPool()->GetDefaultItem( nWhich );
+}
+
+
+const ScPatternAttr* ScDocument::GetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetPattern( nCol, nRow );
+ return NULL;
+}
+
+
+const ScPatternAttr* ScDocument::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow, SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetMostUsedPattern( nCol, nStartRow, nEndRow );
+ return NULL;
+}
+
+
+void ScDocument::ApplyAttr( SCCOL nCol, SCROW nRow, SCTAB nTab, const SfxPoolItem& rAttr )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ApplyAttr( nCol, nRow, rAttr );
+}
+
+
+void ScDocument::ApplyPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->ApplyPattern( nCol, nRow, rAttr );
+}
+
+
+void ScDocument::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark,
+ const ScPatternAttr& rAttr )
+{
+ for (SCTAB i=0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
+}
+
+
+void ScDocument::ApplyPatternAreaTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScPatternAttr& rAttr )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->ApplyPatternArea( nStartCol, nStartRow, nEndCol, nEndRow, rAttr );
+}
+
+void ScDocument::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
+ const ScMarkData& rMark, const ScPatternAttr& rPattern, short nNewType )
+{
+ for (SCTAB i=0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
+}
+
+
+void ScDocument::ApplyStyle( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScStyleSheet& rStyle)
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->ApplyStyle( nCol, nRow, rStyle );
+}
+
+
+void ScDocument::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark,
+ const ScStyleSheet& rStyle)
+{
+ for (SCTAB i=0; i <= MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
+}
+
+
+void ScDocument::ApplyStyleAreaTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, const ScStyleSheet& rStyle)
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->ApplyStyleArea( nStartCol, nStartRow, nEndCol, nEndRow, rStyle );
+}
+
+
+void ScDocument::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
+{
+ // ApplySelectionStyle needs multi mark
+ if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ ScRange aRange;
+ rMark.GetMarkArea( aRange );
+ ApplyStyleArea( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rStyle );
+ }
+ else
+ {
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if ( pTab[i] && rMark.GetTableSelect(i) )
+ pTab[i]->ApplySelectionStyle( rStyle, rMark );
+ }
+}
+
+
+void ScDocument::ApplySelectionLineStyle( const ScMarkData& rMark,
+ const SvxBorderLine* pLine, BOOL bColorOnly )
+{
+ if ( bColorOnly && !pLine )
+ return;
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->ApplySelectionLineStyle( rMark, pLine, bColorOnly );
+}
+
+
+const ScStyleSheet* ScDocument::GetStyle( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ if ( VALIDTAB(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetStyle(nCol, nRow);
+ else
+ return NULL;
+}
+
+
+const ScStyleSheet* ScDocument::GetSelectionStyle( const ScMarkData& rMark ) const
+{
+ BOOL bEqual = TRUE;
+ BOOL bFound;
+
+ const ScStyleSheet* pStyle = NULL;
+ const ScStyleSheet* pNewStyle;
+
+ if ( rMark.IsMultiMarked() )
+ for (SCTAB i=0; i<=MAXTAB && bEqual; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ {
+ pNewStyle = pTab[i]->GetSelectionStyle( rMark, bFound );
+ if (bFound)
+ {
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = FALSE; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+ if ( rMark.IsMarked() )
+ {
+ ScRange aRange;
+ rMark.GetMarkArea( aRange );
+ for (SCTAB i=aRange.aStart.Tab(); i<=aRange.aEnd.Tab() && bEqual; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ {
+ pNewStyle = pTab[i]->GetAreaStyle( bFound,
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ if (bFound)
+ {
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = FALSE; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+
+void ScDocument::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, BOOL bRemoved,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY )
+{
+ for (SCTAB i=0; i <= MAXTAB; i++)
+ if (pTab[i])
+ pTab[i]->StyleSheetChanged
+ ( pStyleSheet, bRemoved, pDev, nPPTX, nPPTY, rZoomX, rZoomY );
+
+ if ( pStyleSheet && pStyleSheet->GetName() == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
+ {
+ // update attributes for all note objects
+ ScDetectiveFunc::UpdateAllComments( *this );
+ }
+}
+
+
+BOOL ScDocument::IsStyleSheetUsed( const ScStyleSheet& rStyle, BOOL bGatherAllStyles ) const
+{
+ if ( bStyleSheetUsageInvalid || rStyle.GetUsage() == ScStyleSheet::UNKNOWN )
+ {
+ if ( bGatherAllStyles )
+ {
+ SfxStyleSheetIterator aIter( xPoolHelper->GetStylePool(),
+ SFX_STYLE_FAMILY_PARA );
+ for ( const SfxStyleSheetBase* pStyle = aIter.First(); pStyle;
+ pStyle = aIter.Next() )
+ {
+ const ScStyleSheet* pScStyle = PTR_CAST( ScStyleSheet, pStyle );
+ if ( pScStyle )
+ pScStyle->SetUsage( ScStyleSheet::NOTUSED );
+ }
+ }
+
+ BOOL bIsUsed = FALSE;
+
+ for ( SCTAB i=0; i<=MAXTAB; i++ )
+ {
+ if ( pTab[i] )
+ {
+ if ( pTab[i]->IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
+ {
+ if ( !bGatherAllStyles )
+ return TRUE;
+ bIsUsed = TRUE;
+ }
+ }
+ }
+
+ if ( bGatherAllStyles )
+ bStyleSheetUsageInvalid = FALSE;
+
+ return bIsUsed;
+ }
+
+ return rStyle.GetUsage() == ScStyleSheet::USED;
+}
+
+
+BOOL ScDocument::ApplyFlagsTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, INT16 nFlags )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->ApplyFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
+
+ DBG_ERROR("ApplyFlags: falsche Tabelle");
+ return FALSE;
+}
+
+
+BOOL ScDocument::RemoveFlagsTab( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab, INT16 nFlags )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->RemoveFlags( nStartCol, nStartRow, nEndCol, nEndRow, nFlags );
+
+ DBG_ERROR("RemoveFlags: falsche Tabelle");
+ return FALSE;
+}
+
+
+void ScDocument::SetPattern( SCCOL nCol, SCROW nRow, SCTAB nTab, const ScPatternAttr& rAttr,
+ BOOL bPutToPool )
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ pTab[nTab]->SetPattern( nCol, nRow, rAttr, bPutToPool );
+}
+
+
+void ScDocument::SetPattern( const ScAddress& rPos, const ScPatternAttr& rAttr,
+ BOOL bPutToPool )
+{
+ SCTAB nTab = rPos.Tab();
+ if (pTab[nTab])
+ pTab[nTab]->SetPattern( rPos, rAttr, bPutToPool );
+}
+
+
+ScPatternAttr* ScDocument::CreateSelectionPattern( const ScMarkData& rMark, BOOL bDeep )
+{
+ ScMergePatternState aState;
+
+ if ( rMark.IsMultiMarked() ) // multi selection
+ {
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->MergeSelectionPattern( aState, rMark, bDeep );
+ }
+ if ( rMark.IsMarked() ) // simle selection
+ {
+ ScRange aRange;
+ rMark.GetMarkArea(aRange);
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->MergePatternArea( aState,
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), bDeep );
+ }
+
+ DBG_ASSERT( aState.pItemSet, "SelectionPattern Null" );
+ if (aState.pItemSet)
+ return new ScPatternAttr( aState.pItemSet );
+ else
+ return new ScPatternAttr( GetPool() ); // empty
+}
+
+
+const ScPatternAttr* ScDocument::GetSelectionPattern( const ScMarkData& rMark, BOOL bDeep )
+{
+ delete pSelectionAttr;
+ pSelectionAttr = CreateSelectionPattern( rMark, bDeep );
+ return pSelectionAttr;
+}
+
+
+void ScDocument::GetSelectionFrame( const ScMarkData& rMark,
+ SvxBoxItem& rLineOuter,
+ SvxBoxInfoItem& rLineInner )
+{
+ rLineOuter.SetLine(NULL, BOX_LINE_TOP);
+ rLineOuter.SetLine(NULL, BOX_LINE_BOTTOM);
+ rLineOuter.SetLine(NULL, BOX_LINE_LEFT);
+ rLineOuter.SetLine(NULL, BOX_LINE_RIGHT);
+ rLineOuter.SetDistance(0);
+
+ rLineInner.SetLine(NULL, BOXINFO_LINE_HORI);
+ rLineInner.SetLine(NULL, BOXINFO_LINE_VERT);
+ rLineInner.SetTable(TRUE);
+ rLineInner.SetDist(TRUE);
+ rLineInner.SetMinDist(FALSE);
+
+ ScLineFlags aFlags;
+
+ if (rMark.IsMarked())
+ {
+ ScRange aRange;
+ rMark.GetMarkArea(aRange);
+ rLineInner.EnableHor( aRange.aStart.Row() != aRange.aEnd.Row() );
+ rLineInner.EnableVer( aRange.aStart.Col() != aRange.aEnd.Col() );
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->MergeBlockFrame( &rLineOuter, &rLineInner, aFlags,
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ }
+
+ // Don't care Status auswerten
+
+ rLineInner.SetValid( VALID_LEFT, ( aFlags.nLeft != SC_LINE_DONTCARE ) );
+ rLineInner.SetValid( VALID_RIGHT, ( aFlags.nRight != SC_LINE_DONTCARE ) );
+ rLineInner.SetValid( VALID_TOP, ( aFlags.nTop != SC_LINE_DONTCARE ) );
+ rLineInner.SetValid( VALID_BOTTOM, ( aFlags.nBottom != SC_LINE_DONTCARE ) );
+ rLineInner.SetValid( VALID_HORI, ( aFlags.nHori != SC_LINE_DONTCARE ) );
+ rLineInner.SetValid( VALID_VERT, ( aFlags.nVert != SC_LINE_DONTCARE ) );
+}
+
+
+BOOL ScDocument::HasAttrib( SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, USHORT nMask )
+{
+ if ( nMask & HASATTR_ROTATE )
+ {
+ // Attribut im Dokument ueberhaupt verwendet?
+ // (wie in fillinfo)
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+
+ BOOL bAnyItem = FALSE;
+ USHORT nRotCount = pPool->GetItemCount( ATTR_ROTATE_VALUE );
+ for (USHORT nItem=0; nItem<nRotCount; nItem++)
+ {
+ const SfxPoolItem* pItem = pPool->GetItem( ATTR_ROTATE_VALUE, nItem );
+ if ( pItem )
+ {
+ // 90 or 270 degrees is former SvxOrientationItem - only look for other values
+ // (see ScPatternAttr::GetCellOrientation)
+ INT32 nAngle = static_cast<const SfxInt32Item*>(pItem)->GetValue();
+ if ( nAngle != 0 && nAngle != 9000 && nAngle != 27000 )
+ {
+ bAnyItem = TRUE;
+ break;
+ }
+ }
+ }
+ if (!bAnyItem)
+ nMask &= ~HASATTR_ROTATE;
+ }
+
+ if ( nMask & HASATTR_RTL )
+ {
+ // first check if right-to left is in the pool at all
+ // (the same item is used in cell and page format)
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+
+ BOOL bHasRtl = FALSE;
+ USHORT nDirCount = pPool->GetItemCount( ATTR_WRITINGDIR );
+ for (USHORT nItem=0; nItem<nDirCount; nItem++)
+ {
+ const SfxPoolItem* pItem = pPool->GetItem( ATTR_WRITINGDIR, nItem );
+ if ( pItem && ((const SvxFrameDirectionItem*)pItem)->GetValue() == FRMDIR_HORI_RIGHT_TOP )
+ {
+ bHasRtl = TRUE;
+ break;
+ }
+ }
+ if (!bHasRtl)
+ nMask &= ~HASATTR_RTL;
+ }
+
+ if (!nMask)
+ return FALSE;
+
+ BOOL bFound = FALSE;
+ for (SCTAB i=nTab1; i<=nTab2 && !bFound; i++)
+ if (pTab[i])
+ {
+ if ( nMask & HASATTR_RTL )
+ {
+ if ( GetEditTextDirection(i) == EE_HTEXTDIR_R2L ) // sheet default
+ bFound = TRUE;
+ }
+ if ( nMask & HASATTR_RIGHTORCENTER )
+ {
+ // On a RTL sheet, don't start to look for the default left value
+ // (which is then logically right), instead always assume TRUE.
+ // That way, ScAttrArray::HasAttrib doesn't have to handle RTL sheets.
+
+ if ( IsLayoutRTL(i) )
+ bFound = TRUE;
+ }
+
+ if ( !bFound )
+ bFound = pTab[i]->HasAttrib( nCol1, nRow1, nCol2, nRow2, nMask );
+ }
+
+ return bFound;
+}
+
+BOOL ScDocument::HasAttrib( const ScRange& rRange, USHORT nMask )
+{
+ return HasAttrib( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
+ nMask );
+}
+
+void ScDocument::FindMaxRotCol( SCTAB nTab, RowInfo* pRowInfo, SCSIZE nArrCount,
+ SCCOL nX1, SCCOL nX2 ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->FindMaxRotCol( pRowInfo, nArrCount, nX1, nX2 );
+ else
+ {
+ DBG_ERRORFILE("FindMaxRotCol: falsche Tabelle");
+ }
+}
+
+void ScDocument::GetBorderLines( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ const SvxBorderLine** ppLeft, const SvxBorderLine** ppTop,
+ const SvxBorderLine** ppRight, const SvxBorderLine** ppBottom ) const
+{
+ //! Seitengrenzen fuer Druck beruecksichtigen !!!!!
+
+ const SvxBoxItem* pThisAttr = (const SvxBoxItem*) GetEffItem( nCol, nRow, nTab, ATTR_BORDER );
+ DBG_ASSERT(pThisAttr,"wo ist das Attribut?");
+
+ const SvxBorderLine* pLeftLine = pThisAttr->GetLeft();
+ const SvxBorderLine* pTopLine = pThisAttr->GetTop();
+ const SvxBorderLine* pRightLine = pThisAttr->GetRight();
+ const SvxBorderLine* pBottomLine = pThisAttr->GetBottom();
+
+ if ( nCol > 0 )
+ {
+ const SvxBorderLine* pOther = ((const SvxBoxItem*)
+ GetEffItem( nCol-1, nRow, nTab, ATTR_BORDER ))->GetRight();
+ if ( ScHasPriority( pOther, pLeftLine ) )
+ pLeftLine = pOther;
+ }
+ if ( nRow > 0 )
+ {
+ const SvxBorderLine* pOther = ((const SvxBoxItem*)
+ GetEffItem( nCol, nRow-1, nTab, ATTR_BORDER ))->GetBottom();
+ if ( ScHasPriority( pOther, pTopLine ) )
+ pTopLine = pOther;
+ }
+ if ( nCol < MAXCOL )
+ {
+ const SvxBorderLine* pOther = ((const SvxBoxItem*)
+ GetEffItem( nCol+1, nRow, nTab, ATTR_BORDER ))->GetLeft();
+ if ( ScHasPriority( pOther, pRightLine ) )
+ pRightLine = pOther;
+ }
+ if ( nRow < MAXROW )
+ {
+ const SvxBorderLine* pOther = ((const SvxBoxItem*)
+ GetEffItem( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
+ if ( ScHasPriority( pOther, pBottomLine ) )
+ pBottomLine = pOther;
+ }
+
+ if (ppLeft)
+ *ppLeft = pLeftLine;
+ if (ppTop)
+ *ppTop = pTopLine;
+ if (ppRight)
+ *ppRight = pRightLine;
+ if (ppBottom)
+ *ppBottom = pBottomLine;
+}
+
+BOOL ScDocument::IsBlockEmpty( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, bool bIgnoreNotes ) const
+{
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->IsBlockEmpty( nStartCol, nStartRow, nEndCol, nEndRow, bIgnoreNotes );
+
+ DBG_ERROR("Falsche Tabellennummer");
+ return FALSE;
+}
+
+
+void ScDocument::LockTable(SCTAB nTab)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->LockTable();
+ else
+ {
+ DBG_ERROR("Falsche Tabellennummer");
+ }
+}
+
+
+void ScDocument::UnlockTable(SCTAB nTab)
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->UnlockTable();
+ else
+ {
+ DBG_ERROR("Falsche Tabellennummer");
+ }
+}
+
+
+BOOL ScDocument::IsBlockEditable( SCTAB nTab, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
+{
+ // import into read-only document is possible
+ if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
+ {
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ return FALSE;
+ }
+
+ if (VALIDTAB(nTab))
+ if (pTab[nTab])
+ return pTab[nTab]->IsBlockEditable( nStartCol, nStartRow, nEndCol,
+ nEndRow, pOnlyNotBecauseOfMatrix );
+
+ DBG_ERROR("Falsche Tabellennummer");
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ return FALSE;
+}
+
+
+BOOL ScDocument::IsSelectionEditable( const ScMarkData& rMark,
+ BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
+{
+ // import into read-only document is possible
+ if ( !bImportingXML && !mbChangeReadOnlyEnabled && pShell && pShell->IsReadOnly() )
+ {
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ return FALSE;
+ }
+
+ ScRange aRange;
+ rMark.GetMarkArea(aRange);
+
+ BOOL bOk = TRUE;
+ BOOL bMatrix = ( pOnlyNotBecauseOfMatrix != NULL );
+ for ( SCTAB i=0; i<=MAXTAB && (bOk || bMatrix); i++ )
+ {
+ if ( pTab[i] && rMark.GetTableSelect(i) )
+ {
+ if (rMark.IsMarked())
+ {
+ if ( !pTab[i]->IsBlockEditable( aRange.aStart.Col(),
+ aRange.aStart.Row(), aRange.aEnd.Col(),
+ aRange.aEnd.Row(), pOnlyNotBecauseOfMatrix ) )
+ {
+ bOk = FALSE;
+ if ( pOnlyNotBecauseOfMatrix )
+ bMatrix = *pOnlyNotBecauseOfMatrix;
+ }
+ }
+ if (rMark.IsMultiMarked())
+ {
+ if ( !pTab[i]->IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix ) )
+ {
+ bOk = FALSE;
+ if ( pOnlyNotBecauseOfMatrix )
+ bMatrix = *pOnlyNotBecauseOfMatrix;
+ }
+ }
+ }
+ }
+
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = ( !bOk && bMatrix );
+
+ return bOk;
+}
+
+
+BOOL ScDocument::HasSelectedBlockMatrixFragment( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark ) const
+{
+ BOOL bOk = TRUE;
+ for (SCTAB i=0; i<=MAXTAB && bOk; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ if (pTab[i]->HasBlockMatrixFragment( nStartCol, nStartRow, nEndCol, nEndRow ))
+ bOk = FALSE;
+
+ return !bOk;
+}
+
+
+BOOL ScDocument::GetMatrixFormulaRange( const ScAddress& rCellPos, ScRange& rMatrix )
+{
+ // if rCell is part of a matrix formula, return its complete range
+
+ BOOL bRet = FALSE;
+ ScBaseCell* pCell = GetCell( rCellPos );
+ if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ ScAddress aOrigin = rCellPos;
+ if ( ((ScFormulaCell*)pCell)->GetMatrixOrigin( aOrigin ) )
+ {
+ if ( aOrigin != rCellPos )
+ pCell = GetCell( aOrigin );
+ if (pCell && pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ SCCOL nSizeX;
+ SCROW nSizeY;
+ ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
+ if ( !(nSizeX > 0 && nSizeY > 0) )
+ {
+ // GetMatrixEdge computes also dimensions of the matrix
+ // if not already done (may occur if document is loaded
+ // from old file format).
+ // Needs an "invalid" initialized address.
+ aOrigin.SetInvalid();
+ ((ScFormulaCell*)pCell)->GetMatrixEdge(aOrigin);
+ ((ScFormulaCell*)pCell)->GetMatColsRows(nSizeX,nSizeY);
+ }
+ if ( nSizeX > 0 && nSizeY > 0 )
+ {
+ ScAddress aEnd( aOrigin.Col() + nSizeX - 1,
+ aOrigin.Row() + nSizeY - 1,
+ aOrigin.Tab() );
+
+ rMatrix.aStart = aOrigin;
+ rMatrix.aEnd = aEnd;
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+
+BOOL ScDocument::ExtendOverlapped( SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
+{
+ BOOL bFound = FALSE;
+ if ( ValidColRow(rStartCol,rStartRow) && ValidColRow(nEndCol,nEndRow) && ValidTab(nTab) )
+ {
+ if (pTab[nTab])
+ {
+ SCCOL nCol;
+ SCCOL nOldCol = rStartCol;
+ SCROW nOldRow = rStartRow;
+ for (nCol=nOldCol; nCol<=nEndCol; nCol++)
+ while (((ScMergeFlagAttr*)GetAttr(nCol,rStartRow,nTab,ATTR_MERGE_FLAG))->
+ IsVerOverlapped())
+ --rStartRow;
+
+ //! weiterreichen ?
+
+ ScAttrArray* pAttrArray = pTab[nTab]->aCol[nOldCol].pAttrArray;
+ SCSIZE nIndex;
+ pAttrArray->Search( nOldRow, nIndex );
+ SCROW nAttrPos = nOldRow;
+ while (nAttrPos<=nEndRow)
+ {
+ DBG_ASSERT( nIndex < pAttrArray->nCount, "Falscher Index im AttrArray" );
+
+ if (((ScMergeFlagAttr&)pAttrArray->pData[nIndex].pPattern->
+ GetItem(ATTR_MERGE_FLAG)).IsHorOverlapped())
+ {
+ SCROW nLoopEndRow = Min( nEndRow, pAttrArray->pData[nIndex].nRow );
+ for (SCROW nAttrRow = nAttrPos; nAttrRow <= nLoopEndRow; nAttrRow++)
+ {
+ SCCOL nTempCol = nOldCol;
+ do
+ --nTempCol;
+ while (((ScMergeFlagAttr*)GetAttr(nTempCol,nAttrRow,nTab,ATTR_MERGE_FLAG))
+ ->IsHorOverlapped());
+ if (nTempCol < rStartCol)
+ rStartCol = nTempCol;
+ }
+ }
+ nAttrPos = pAttrArray->pData[nIndex].nRow + 1;
+ ++nIndex;
+ }
+ }
+ }
+ else
+ {
+ DBG_ERROR("ExtendOverlapped: falscher Bereich");
+ }
+
+ return bFound;
+}
+
+
+BOOL ScDocument::ExtendMergeSel( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow,
+ const ScMarkData& rMark, BOOL bRefresh, BOOL bAttrs )
+{
+ // use all selected sheets from rMark
+
+ BOOL bFound = FALSE;
+ SCCOL nOldEndCol = rEndCol;
+ SCROW nOldEndRow = rEndRow;
+
+ for (SCTAB nTab = 0; nTab <= MAXTAB; nTab++)
+ if ( pTab[nTab] && rMark.GetTableSelect(nTab) )
+ {
+ SCCOL nThisEndCol = nOldEndCol;
+ SCROW nThisEndRow = nOldEndRow;
+ if ( ExtendMerge( nStartCol, nStartRow, nThisEndCol, nThisEndRow, nTab, bRefresh, bAttrs ) )
+ bFound = TRUE;
+ if ( nThisEndCol > rEndCol )
+ rEndCol = nThisEndCol;
+ if ( nThisEndRow > rEndRow )
+ rEndRow = nThisEndRow;
+ }
+
+ return bFound;
+}
+
+
+BOOL ScDocument::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow,
+ SCTAB nTab, BOOL bRefresh, BOOL bAttrs )
+{
+ BOOL bFound = FALSE;
+ if ( ValidColRow(nStartCol,nStartRow) && ValidColRow(rEndCol,rEndRow) && ValidTab(nTab) )
+ {
+ if (pTab[nTab])
+ bFound = pTab[nTab]->ExtendMerge( nStartCol, nStartRow, rEndCol, rEndRow, bRefresh, bAttrs );
+
+ if (bRefresh)
+ RefreshAutoFilter( nStartCol, nStartRow, rEndCol, rEndRow, nTab );
+ }
+ else
+ {
+ DBG_ERROR("ExtendMerge: falscher Bereich");
+ }
+
+ return bFound;
+}
+
+
+BOOL ScDocument::ExtendMerge( ScRange& rRange, BOOL bRefresh, BOOL bAttrs )
+{
+ BOOL bFound = FALSE;
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+
+ PutInOrder( nStartTab, nEndTab );
+ for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
+ {
+ SCCOL nExtendCol = rRange.aEnd.Col();
+ SCROW nExtendRow = rRange.aEnd.Row();
+ if (ExtendMerge( rRange.aStart.Col(), rRange.aStart.Row(),
+ nExtendCol, nExtendRow,
+ nTab, bRefresh, bAttrs ) )
+ {
+ bFound = TRUE;
+ if (nExtendCol > nEndCol) nEndCol = nExtendCol;
+ if (nExtendRow > nEndRow) nEndRow = nExtendRow;
+ }
+ }
+
+ rRange.aEnd.SetCol(nEndCol);
+ rRange.aEnd.SetRow(nEndRow);
+
+ return bFound;
+}
+
+BOOL ScDocument::ExtendTotalMerge( ScRange& rRange )
+{
+ // Bereich genau dann auf zusammengefasste Zellen erweitern, wenn
+ // dadurch keine neuen nicht-ueberdeckten Zellen getroffen werden
+
+ BOOL bRet = FALSE;
+ ScRange aExt = rRange;
+ if (ExtendMerge(aExt))
+ {
+ if ( aExt.aEnd.Row() > rRange.aEnd.Row() )
+ {
+ ScRange aTest = aExt;
+ aTest.aStart.SetRow( rRange.aEnd.Row() + 1 );
+ if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
+ aExt.aEnd.SetRow(rRange.aEnd.Row());
+ }
+ if ( aExt.aEnd.Col() > rRange.aEnd.Col() )
+ {
+ ScRange aTest = aExt;
+ aTest.aStart.SetCol( rRange.aEnd.Col() + 1 );
+ if ( HasAttrib( aTest, HASATTR_NOTOVERLAPPED ) )
+ aExt.aEnd.SetCol(rRange.aEnd.Col());
+ }
+
+ bRet = ( aExt.aEnd != rRange.aEnd );
+ rRange = aExt;
+ }
+ return bRet;
+}
+
+BOOL ScDocument::ExtendOverlapped( ScRange& rRange )
+{
+ BOOL bFound = FALSE;
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+
+ PutInOrder( nStartTab, nEndTab );
+ for (SCTAB nTab = nStartTab; nTab <= nEndTab; nTab++ )
+ {
+ SCCOL nExtendCol = rRange.aStart.Col();
+ SCROW nExtendRow = rRange.aStart.Row();
+ ExtendOverlapped( nExtendCol, nExtendRow,
+ rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
+ if (nExtendCol < nStartCol)
+ {
+ nStartCol = nExtendCol;
+ bFound = TRUE;
+ }
+ if (nExtendRow < nStartRow)
+ {
+ nStartRow = nExtendRow;
+ bFound = TRUE;
+ }
+ }
+
+ rRange.aStart.SetCol(nStartCol);
+ rRange.aStart.SetRow(nStartRow);
+
+ return bFound;
+}
+
+BOOL ScDocument::RefreshAutoFilter( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nTab )
+{
+ USHORT nCount = pDBCollection->GetCount();
+ USHORT i;
+ ScDBData* pData;
+ SCTAB nDBTab;
+ SCCOL nDBStartCol;
+ SCROW nDBStartRow;
+ SCCOL nDBEndCol;
+ SCROW nDBEndRow;
+
+ // Autofilter loeschen
+
+ BOOL bChange = RemoveFlagsTab( nStartCol,nStartRow, nEndCol,nEndRow, nTab, SC_MF_AUTO );
+
+ // Autofilter setzen
+
+ for (i=0; i<nCount; i++)
+ {
+ pData = (*pDBCollection)[i];
+ if (pData->HasAutoFilter())
+ {
+ pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
+ if ( nDBTab==nTab && nDBStartRow<=nEndRow && nDBEndRow>=nStartRow &&
+ nDBStartCol<=nEndCol && nDBEndCol>=nStartCol )
+ {
+ if (ApplyFlagsTab( nDBStartCol,nDBStartRow, nDBEndCol,nDBStartRow,
+ nDBTab, SC_MF_AUTO ))
+ bChange = TRUE;
+ }
+ }
+ }
+ return bChange;
+}
+
+
+//UNUSED2008-05 void ScDocument::SetAutoFilterFlags()
+//UNUSED2008-05 {
+//UNUSED2008-05 USHORT nCount = pDBCollection->GetCount();
+//UNUSED2008-05 for (USHORT i=0; i<nCount; i++)
+//UNUSED2008-05 {
+//UNUSED2008-05 ScDBData* pData = (*pDBCollection)[i];
+//UNUSED2008-05 SCTAB nDBTab;
+//UNUSED2008-05 SCCOL nDBStartCol;
+//UNUSED2008-05 SCROW nDBStartRow;
+//UNUSED2008-05 SCCOL nDBEndCol;
+//UNUSED2008-05 SCROW nDBEndRow;
+//UNUSED2008-05 pData->GetArea( nDBTab, nDBStartCol,nDBStartRow, nDBEndCol,nDBEndRow );
+//UNUSED2008-05 pData->SetAutoFilter( HasAttrib( nDBStartCol,nDBStartRow,nDBTab,
+//UNUSED2008-05 nDBEndCol,nDBStartRow,nDBTab, HASATTR_AUTOFILTER ) );
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+
+
+BOOL ScDocument::IsHorOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
+ GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
+ if (pAttr)
+ return pAttr->IsHorOverlapped();
+ else
+ {
+ DBG_ERROR("Overlapped: Attr==0");
+ return FALSE;
+ }
+}
+
+
+BOOL ScDocument::IsVerOverlapped( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ const ScMergeFlagAttr* pAttr = (const ScMergeFlagAttr*)
+ GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG );
+ if (pAttr)
+ return pAttr->IsVerOverlapped();
+ else
+ {
+ DBG_ERROR("Overlapped: Attr==0");
+ return FALSE;
+ }
+}
+
+
+void ScDocument::ApplySelectionFrame( const ScMarkData& rMark,
+ const SvxBoxItem* pLineOuter,
+ const SvxBoxInfoItem* pLineInner )
+{
+ if (rMark.IsMarked())
+ {
+ ScRange aRange;
+ rMark.GetMarkArea(aRange);
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i])
+ if (rMark.GetTableSelect(i))
+ pTab[i]->ApplyBlockFrame( pLineOuter, pLineInner,
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ }
+}
+
+
+void ScDocument::ApplyFrameAreaTab( const ScRange& rRange,
+ const SvxBoxItem* pLineOuter,
+ const SvxBoxInfoItem* pLineInner )
+{
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCTAB nEndTab = rRange.aStart.Tab();
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ if (pTab[nTab])
+ pTab[nTab]->ApplyBlockFrame( pLineOuter, pLineInner,
+ rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row() );
+}
+
+
+void ScDocument::ApplySelectionPattern( const ScPatternAttr& rAttr, const ScMarkData& rMark )
+{
+ const SfxItemSet* pSet = &rAttr.GetItemSet();
+ BOOL bSet = FALSE;
+ USHORT i;
+ for (i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END && !bSet; i++)
+ if (pSet->GetItemState(i) == SFX_ITEM_SET)
+ bSet = TRUE;
+
+ if (bSet)
+ {
+ // ApplySelectionCache needs multi mark
+ if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ ScRange aRange;
+ rMark.GetMarkArea( aRange );
+ ApplyPatternArea( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), rMark, rAttr );
+ }
+ else
+ {
+ SfxItemPoolCache aCache( xPoolHelper->GetDocPool(), pSet );
+ for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
+ if (pTab[nTab])
+ if (rMark.GetTableSelect(nTab))
+ pTab[nTab]->ApplySelectionCache( &aCache, rMark );
+ }
+ }
+}
+
+
+void ScDocument::ChangeSelectionIndent( BOOL bIncrement, const ScMarkData& rMark )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->ChangeSelectionIndent( bIncrement, rMark );
+}
+
+
+void ScDocument::ClearSelectionItems( const USHORT* pWhich, const ScMarkData& rMark )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->ClearSelectionItems( pWhich, rMark );
+}
+
+
+void ScDocument::DeleteSelection( USHORT nDelFlag, const ScMarkData& rMark )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (pTab[i] && rMark.GetTableSelect(i))
+ pTab[i]->DeleteSelection( nDelFlag, rMark );
+}
+
+
+void ScDocument::DeleteSelectionTab( SCTAB nTab, USHORT nDelFlag, const ScMarkData& rMark )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->DeleteSelection( nDelFlag, rMark );
+ else
+ {
+ DBG_ERROR("Falsche Tabelle");
+ }
+}
+
+
+ScPatternAttr* ScDocument::GetDefPattern() const
+{
+ return (ScPatternAttr*) &xPoolHelper->GetDocPool()->GetDefaultItem(ATTR_PATTERN);
+}
+
+
+ScDocumentPool* ScDocument::GetPool()
+{
+ return xPoolHelper->GetDocPool();
+}
+
+
+
+ScStyleSheetPool* ScDocument::GetStyleSheetPool() const
+{
+ return xPoolHelper->GetStylePool();
+}
+
+
+SCSIZE ScDocument::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir )
+{
+ PutInOrder(nStartCol, nEndCol);
+ PutInOrder(nStartRow, nEndRow);
+ PutInOrder(nStartTab, nEndTab);
+ if (VALIDTAB(nStartTab))
+ {
+ if (pTab[nStartTab])
+ return pTab[nStartTab]->GetEmptyLinesInBlock(nStartCol, nStartRow, nEndCol, nEndRow, eDir);
+ else
+ return 0;
+ }
+ else
+ return 0;
+}
+
+
+void ScDocument::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->FindAreaPos( rCol, rRow, nMovX, nMovY );
+}
+
+
+void ScDocument::GetNextPos( SCCOL& rCol, SCROW& rRow, SCTAB nTab, SCsCOL nMovX, SCsROW nMovY,
+ BOOL bMarked, BOOL bUnprotected, const ScMarkData& rMark )
+{
+ DBG_ASSERT( !nMovX || !nMovY, "GetNextPos: nur X oder Y" );
+
+ ScMarkData aCopyMark = rMark;
+ aCopyMark.SetMarking(FALSE);
+ aCopyMark.MarkToMulti();
+
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->GetNextPos( rCol, rRow, nMovX, nMovY, bMarked, bUnprotected, aCopyMark );
+}
+
+//
+// Datei-Operationen
+//
+
+
+void ScDocument::UpdStlShtPtrsFrmNms()
+{
+ ScPatternAttr::pDoc = this;
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+
+ USHORT nCount = pPool->GetItemCount(ATTR_PATTERN);
+ ScPatternAttr* pPattern;
+ for (USHORT i=0; i<nCount; i++)
+ {
+ pPattern = (ScPatternAttr*)pPool->GetItem(ATTR_PATTERN, i);
+ if (pPattern)
+ pPattern->UpdateStyleSheet();
+ }
+ ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).UpdateStyleSheet();
+}
+
+
+void ScDocument::StylesToNames()
+{
+ ScPatternAttr::pDoc = this;
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+
+ USHORT nCount = pPool->GetItemCount(ATTR_PATTERN);
+ ScPatternAttr* pPattern;
+ for (USHORT i=0; i<nCount; i++)
+ {
+ pPattern = (ScPatternAttr*)pPool->GetItem(ATTR_PATTERN, i);
+ if (pPattern)
+ pPattern->StyleToName();
+ }
+ ((ScPatternAttr&)pPool->GetDefaultItem(ATTR_PATTERN)).StyleToName();
+}
+
+
+ULONG ScDocument::GetCellCount() const
+{
+ ULONG nCellCount = 0L;
+
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] )
+ nCellCount += pTab[nTab]->GetCellCount();
+
+ return nCellCount;
+}
+
+
+ULONG ScDocument::GetCodeCount() const
+{
+ ULONG nCodeCount = 0;
+
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] )
+ nCodeCount += pTab[nTab]->GetCodeCount();
+
+ return nCodeCount;
+}
+
+
+ULONG ScDocument::GetWeightedCount() const
+{
+ ULONG nCellCount = 0L;
+
+ for ( SCTAB nTab=0; nTab<=MAXTAB; nTab++ )
+ if ( pTab[nTab] )
+ nCellCount += pTab[nTab]->GetWeightedCount();
+
+ return nCellCount;
+}
+
+
+void ScDocument::PageStyleModified( SCTAB nTab, const String& rNewName )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->PageStyleModified( rNewName );
+}
+
+
+void ScDocument::SetPageStyle( SCTAB nTab, const String& rName )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetPageStyle( rName );
+}
+
+
+const String& ScDocument::GetPageStyle( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetPageStyle();
+
+ return EMPTY_STRING;
+}
+
+
+void ScDocument::SetPageSize( SCTAB nTab, const Size& rSize )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetPageSize( rSize );
+}
+
+Size ScDocument::GetPageSize( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->GetPageSize();
+
+ DBG_ERROR("falsche Tab");
+ return Size();
+}
+
+
+void ScDocument::SetRepeatArea( SCTAB nTab, SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->SetRepeatArea( nStartCol, nEndCol, nStartRow, nEndRow );
+}
+
+
+void ScDocument::UpdatePageBreaks( SCTAB nTab, const ScRange* pUserArea )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->UpdatePageBreaks( pUserArea );
+}
+
+void ScDocument::RemoveManualBreaks( SCTAB nTab )
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ pTab[nTab]->RemoveManualBreaks();
+}
+
+BOOL ScDocument::HasManualBreaks( SCTAB nTab ) const
+{
+ if ( ValidTab(nTab) && pTab[nTab] )
+ return pTab[nTab]->HasManualBreaks();
+
+ DBG_ERROR("falsche Tab");
+ return FALSE;
+}
+
+
+void ScDocument::GetDocStat( ScDocStat& rDocStat )
+{
+ rDocStat.nTableCount = GetTableCount();
+ rDocStat.aDocName = aDocName;
+ rDocStat.nCellCount = GetCellCount();
+}
+
+
+BOOL ScDocument::HasPrintRange()
+{
+ BOOL bResult = FALSE;
+
+ for ( SCTAB i=0; !bResult && i<nMaxTableNumber; i++ )
+ if ( pTab[i] )
+ bResult = pTab[i]->IsPrintEntireSheet() || (pTab[i]->GetPrintRangeCount() > 0);
+
+ return bResult;
+}
+
+
+BOOL ScDocument::IsPrintEntireSheet( SCTAB nTab ) const
+{
+ return (ValidTab(nTab) ) && pTab[nTab] && pTab[nTab]->IsPrintEntireSheet();
+}
+
+
+USHORT ScDocument::GetPrintRangeCount( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetPrintRangeCount();
+
+ return 0;
+}
+
+
+const ScRange* ScDocument::GetPrintRange( SCTAB nTab, USHORT nPos )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetPrintRange(nPos);
+
+ return NULL;
+}
+
+
+const ScRange* ScDocument::GetRepeatColRange( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetRepeatColRange();
+
+ return NULL;
+}
+
+
+const ScRange* ScDocument::GetRepeatRowRange( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ return pTab[nTab]->GetRepeatRowRange();
+
+ return NULL;
+}
+
+
+void ScDocument::ClearPrintRanges( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->ClearPrintRanges();
+}
+
+
+void ScDocument::AddPrintRange( SCTAB nTab, const ScRange& rNew )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->AddPrintRange( rNew );
+}
+
+
+void ScDocument::SetPrintRange( SCTAB nTab, const ScRange& rNew )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetPrintRange( rNew );
+}
+
+
+void ScDocument::SetPrintEntireSheet( SCTAB nTab )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetPrintEntireSheet();
+}
+
+
+void ScDocument::SetRepeatColRange( SCTAB nTab, const ScRange* pNew )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetRepeatColRange( pNew );
+}
+
+
+void ScDocument::SetRepeatRowRange( SCTAB nTab, const ScRange* pNew )
+{
+ if (ValidTab(nTab) && pTab[nTab])
+ pTab[nTab]->SetRepeatRowRange( pNew );
+}
+
+
+ScPrintRangeSaver* ScDocument::CreatePrintRangeSaver() const
+{
+ SCTAB nCount = GetTableCount();
+ ScPrintRangeSaver* pNew = new ScPrintRangeSaver( nCount );
+ for (SCTAB i=0; i<nCount; i++)
+ if (pTab[i])
+ pTab[i]->FillPrintSaver( pNew->GetTabData(i) );
+ return pNew;
+}
+
+
+void ScDocument::RestorePrintRanges( const ScPrintRangeSaver& rSaver )
+{
+ SCTAB nCount = rSaver.GetTabCount();
+ for (SCTAB i=0; i<nCount; i++)
+ if (pTab[i])
+ pTab[i]->RestorePrintRanges( rSaver.GetTabData(i) );
+}
+
+
+BOOL ScDocument::NeedPageResetAfterTab( SCTAB nTab ) const
+{
+ // Die Seitennummern-Zaehlung faengt bei einer Tabelle neu an, wenn eine
+ // andere Vorlage als bei der vorherigen gesetzt ist (nur Namen vergleichen)
+ // und eine Seitennummer angegeben ist (nicht 0)
+
+ if ( nTab < MAXTAB && pTab[nTab] && pTab[nTab+1] )
+ {
+ String aNew = pTab[nTab+1]->GetPageStyle();
+ if ( aNew != pTab[nTab]->GetPageStyle() )
+ {
+ SfxStyleSheetBase* pStyle = xPoolHelper->GetStylePool()->Find( aNew, SFX_STYLE_FAMILY_PAGE );
+ if ( pStyle )
+ {
+ const SfxItemSet& rSet = pStyle->GetItemSet();
+ USHORT nFirst = ((const SfxUInt16Item&)rSet.Get(ATTR_PAGE_FIRSTPAGENO)).GetValue();
+ if ( nFirst != 0 )
+ return TRUE; // Seitennummer in neuer Vorlage angegeben
+ }
+ }
+ }
+
+ return FALSE; // sonst nicht
+}
+
+
+
diff --git a/sc/source/core/data/dpcachetable.cxx b/sc/source/core/data/dpcachetable.cxx
new file mode 100644
index 000000000000..2a1b4481ccaa
--- /dev/null
+++ b/sc/source/core/data/dpcachetable.cxx
@@ -0,0 +1,716 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dpcachetable.cxx,v $
+ *
+ * $Revision: 1.6 $
+ *
+ * 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 "dpcachetable.hxx"
+#include "document.hxx"
+#include "address.hxx"
+#include "cell.hxx"
+#include "dptabdat.hxx"
+#include "dptabsrc.hxx"
+#include "dpobject.hxx"
+
+#include <com/sun/star/i18n/LocaleDataItem.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+
+using ::rtl::OUString;
+using ::std::vector;
+using ::std::pair;
+using ::std::hash_map;
+using ::std::hash_set;
+using ::std::auto_ptr;
+using ::com::sun::star::i18n::LocaleDataItem;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::sheet::DataPilotFieldFilter;
+
+const double D_TIMEFACTOR = 86400.0;
+
+static BOOL lcl_HasQueryEntry( const ScQueryParam& rParam )
+{
+ return rParam.GetEntryCount() > 0 &&
+ rParam.GetEntry(0).bDoQuery;
+}
+
+// ----------------------------------------------------------------------------
+
+static ScDPCacheCell EmptyCellContent = ScDPCacheCell();
+
+// ----------------------------------------------------------------------------
+
+ScDPCacheTable::Cell::Cell() :
+ mnCategoryRef(0),
+ mpContent(NULL)
+{
+}
+
+ScDPCacheTable::Cell::~Cell()
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPCacheTable::FilterItem::FilterItem() :
+ mnMatchStrId(ScSimpleSharedString::EMPTY),
+ mfValue(0.0),
+ mbHasValue(false)
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPCacheTable::SingleFilter::SingleFilter(ScSimpleSharedString& rSharedString,
+ sal_Int32 nMatchStrId, double fValue, bool bHasValue) :
+ mrSharedString(rSharedString)
+{
+ maItem.mnMatchStrId = nMatchStrId;
+ maItem.mfValue = fValue;
+ maItem.mbHasValue = bHasValue;
+}
+
+bool ScDPCacheTable::SingleFilter::match(const ScDPCacheCell& rCell) const
+{
+ if (rCell.mnStrId != maItem.mnMatchStrId &&
+ (!rCell.mbNumeric || rCell.mfValue != maItem.mfValue))
+ return false;
+
+ return true;
+}
+
+const String ScDPCacheTable::SingleFilter::getMatchString()
+{
+ const String* pStr = mrSharedString.getString(maItem.mnMatchStrId);
+ if (pStr)
+ return *pStr;
+
+ return String();
+}
+
+double ScDPCacheTable::SingleFilter::getMatchValue() const
+{
+ return maItem.mfValue;
+}
+
+bool ScDPCacheTable::SingleFilter::hasValue() const
+{
+ return maItem.mbHasValue;
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPCacheTable::GroupFilter::GroupFilter(ScSimpleSharedString& rSharedString) :
+ mrSharedString(rSharedString)
+{
+}
+
+bool ScDPCacheTable::GroupFilter::match(const ScDPCacheCell& rCell) const
+{
+ vector<FilterItem>::const_iterator itrEnd = maItems.end();
+ for (vector<FilterItem>::const_iterator itr = maItems.begin(); itr != itrEnd; ++itr)
+ {
+ bool bMatch = false;
+ if (rCell.mbNumeric)
+ bMatch = (itr->mfValue == rCell.mfValue);
+ else
+ bMatch = (itr->mnMatchStrId == rCell.mnStrId);
+
+ if (bMatch)
+ return true;
+ }
+ return false;
+}
+
+void ScDPCacheTable::GroupFilter::addMatchItem(const String& rStr, double fVal, bool bHasValue)
+{
+ sal_Int32 nStrId = mrSharedString.getStringId(rStr);
+ FilterItem aItem;
+ aItem.mnMatchStrId = nStrId;
+ aItem.mfValue = fVal;
+ aItem.mbHasValue = bHasValue;
+ maItems.push_back(aItem);
+}
+
+size_t ScDPCacheTable::GroupFilter::getMatchItemCount() const
+{
+ return maItems.size();
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPCacheTable::Criterion::Criterion() :
+ mnFieldIndex(-1),
+ mpFilter(static_cast<FilterBase*>(NULL))
+{
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPCacheTable::ScDPCacheTable(ScDPCollection* pCollection) :
+ mrSharedString(pCollection->GetSharedString()),
+ mpCollection(pCollection)
+{
+}
+
+ScDPCacheTable::~ScDPCacheTable()
+{
+}
+
+sal_Int32 ScDPCacheTable::getRowSize() const
+{
+ return maTable.size();
+}
+
+sal_Int32 ScDPCacheTable::getColSize() const
+{
+ return maTable.empty() ? 0 : maTable[0].size();
+}
+
+void ScDPCacheTable::fillTable(ScDocument* pDoc, const ScRange& rRange, const ScQueryParam& rQuery, BOOL* pSpecial,
+ bool bIgnoreEmptyRows)
+{
+ SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nColCount = rRange.aEnd.Col() - rRange.aStart.Col() + 1;
+ SCROW nRowCount = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
+
+ if (nRowCount <= 1 || nColCount <= 0)
+ return;
+
+ maTable.clear();
+ maTable.reserve(nRowCount);
+ maHeader.clear();
+ maHeader.reserve(nColCount);
+ maRowsVisible.clear();
+ maRowsVisible.reserve(nRowCount);
+
+ // Header row
+ for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
+ {
+ String aStr;
+ pDoc->GetString(nCol + nStartCol, nStartRow, nTab, aStr);
+ sal_Int32 nStrId = mrSharedString.insertString(aStr);
+ maHeader.push_back(nStrId);
+ }
+
+ // Initialize field entries container.
+ maFieldEntries.clear();
+ maFieldEntries.reserve(nColCount);
+ for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
+ {
+ TypedScStrCollectionPtr p(new TypedScStrCollection);
+ maFieldEntries.push_back(p);
+ }
+
+ vector<SCROW> aLastNonEmptyRows(nColCount, 0);
+
+ // Data rows
+ for (SCROW nRow = 1; nRow < nRowCount; ++nRow)
+ {
+ if ( lcl_HasQueryEntry(rQuery) && !pDoc->ValidQuery(nRow + nStartRow, nTab, rQuery, pSpecial) )
+ // filtered out by standard filter.
+ continue;
+
+ if ( bIgnoreEmptyRows &&
+ pDoc->IsBlockEmpty(nTab, nStartCol, nRow + nStartRow,
+ nStartCol + nColCount - 1, nRow + nStartRow) )
+ // skip an empty row.
+ continue;
+
+ // Insert a new row into cache table.
+ maRowsVisible.push_back(true);
+ maTable.push_back( vector<Cell>() );
+ maTable.back().reserve(nColCount);
+
+ for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
+ {
+ maTable.back().push_back( ScDPCacheTable::Cell() );
+ Cell& rCell = maTable.back().back();
+ rCell.mnCategoryRef = maTable.size()-1;
+
+ String aCellStr;
+ bool bReadCell = nRow == 0 || pDoc->HasData(nStartCol + nCol, nStartRow + nRow, nTab);
+ if (bReadCell)
+ {
+ aLastNonEmptyRows[nCol] = maTable.size()-1;
+ ScDPCacheCell aCell;
+ pDoc->GetString(nStartCol + nCol, nStartRow + nRow, nTab, aCellStr);
+ aCell.mnStrId = mrSharedString.insertString(aCellStr);
+ aCell.mnType = SC_VALTYPE_STRING;
+ aCell.mbNumeric = false;
+ ScAddress aPos(nStartCol + nCol, nStartRow + nRow, nTab);
+ getValueData(pDoc, aPos, aCell);
+ rCell.mpContent = mpCollection->getCacheCellFromPool(aCell);
+ }
+ else
+ rCell.mnCategoryRef = aLastNonEmptyRows[nCol];
+
+ TypedStrData* pNew;
+ if (rCell.mpContent && rCell.mpContent->mbNumeric)
+ pNew = new TypedStrData(aCellStr, rCell.mpContent->mfValue, SC_STRTYPE_VALUE);
+ else
+ pNew = new TypedStrData(aCellStr);
+
+ if (!maFieldEntries[nCol]->Insert(pNew))
+ delete pNew;
+ }
+ }
+}
+
+void lcl_GetCellValue(const Reference<sdbc::XRow>& xRow, sal_Int32 nType, long nCol,
+ const Date& rNullDate, ScDPCacheCell& rCell, String& rStr,
+ ScSimpleSharedString& rSharedString)
+{
+ short nNumType = NUMBERFORMAT_NUMBER;
+ BOOL bEmptyFlag = FALSE;
+ try
+ {
+ rStr = xRow->getString(nCol);
+ rCell.mnStrId = rSharedString.getStringId(rStr);
+ rCell.mnType = SC_VALTYPE_STRING;
+
+ switch (nType)
+ {
+ case sdbc::DataType::BIT:
+ case sdbc::DataType::BOOLEAN:
+ {
+ nNumType = NUMBERFORMAT_LOGICAL;
+ rCell.mfValue = xRow->getBoolean(nCol) ? 1 : 0;
+ bEmptyFlag = (rCell.mfValue == 0.0 && xRow->wasNull());
+ rCell.mbNumeric = true;
+ rCell.mnType = SC_VALTYPE_VALUE;
+ }
+ break;
+
+ case sdbc::DataType::TINYINT:
+ case sdbc::DataType::SMALLINT:
+ case sdbc::DataType::INTEGER:
+ case sdbc::DataType::BIGINT:
+ case sdbc::DataType::FLOAT:
+ case sdbc::DataType::REAL:
+ case sdbc::DataType::DOUBLE:
+ case sdbc::DataType::NUMERIC:
+ case sdbc::DataType::DECIMAL:
+ {
+ //! do the conversion here?
+ rCell.mfValue = xRow->getDouble(nCol);
+ bEmptyFlag = (rCell.mfValue == 0.0 && xRow->wasNull());
+ rCell.mbNumeric = true;
+ rCell.mnType = SC_VALTYPE_VALUE;
+ }
+ break;
+
+ case sdbc::DataType::CHAR:
+ case sdbc::DataType::VARCHAR:
+ case sdbc::DataType::LONGVARCHAR:
+ bEmptyFlag = (rStr.Len() == 0 && xRow->wasNull());
+ break;
+
+ case sdbc::DataType::DATE:
+ {
+ nNumType = NUMBERFORMAT_DATE;
+
+ util::Date aDate = xRow->getDate(nCol);
+ rCell.mfValue = Date(aDate.Day, aDate.Month, aDate.Year) - rNullDate;
+ bEmptyFlag = xRow->wasNull();
+ rCell.mbNumeric = true;
+ rCell.mnType = SC_VALTYPE_VALUE;
+ }
+ break;
+
+ case sdbc::DataType::TIME:
+ {
+ nNumType = NUMBERFORMAT_TIME;
+
+ util::Time aTime = xRow->getTime(nCol);
+ rCell.mfValue = ( aTime.Hours * 3600 + aTime.Minutes * 60 +
+ aTime.Seconds + aTime.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
+ bEmptyFlag = xRow->wasNull();
+ rCell.mbNumeric = true;
+ rCell.mnType = SC_VALTYPE_VALUE;
+ }
+ break;
+
+ case sdbc::DataType::TIMESTAMP:
+ {
+ nNumType = NUMBERFORMAT_DATETIME;
+
+ util::DateTime aStamp = xRow->getTimestamp(nCol);
+ rCell.mfValue = ( Date( aStamp.Day, aStamp.Month, aStamp.Year ) - rNullDate ) +
+ ( aStamp.Hours * 3600 + aStamp.Minutes * 60 +
+ aStamp.Seconds + aStamp.HundredthSeconds / 100.0 ) / D_TIMEFACTOR;
+ bEmptyFlag = xRow->wasNull();
+ rCell.mbNumeric = true;
+ rCell.mnType = SC_VALTYPE_VALUE;
+ }
+ break;
+
+ case sdbc::DataType::SQLNULL:
+ case sdbc::DataType::BINARY:
+ case sdbc::DataType::VARBINARY:
+ case sdbc::DataType::LONGVARBINARY:
+ default:
+ break;
+ }
+ }
+ catch (uno::Exception&)
+ {
+ }
+}
+
+void ScDPCacheTable::fillTable(const Reference<sdbc::XRowSet>& xRowSet, const Date& rNullDate)
+{
+ if (!xRowSet.is())
+ // Dont' even waste time to go any further.
+ return;
+
+ try
+ {
+ Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp(xRowSet, UNO_QUERY_THROW);
+ Reference<sdbc::XResultSetMetaData> xMeta = xMetaSupp->getMetaData();
+ if (!xMeta.is())
+ return;
+
+ sal_Int32 nColCount = xMeta->getColumnCount();
+
+ // Get column titles and types.
+ vector<sal_Int32> aColTypes(nColCount);
+ maHeader.clear();
+ maHeader.reserve(nColCount);
+ for (sal_Int32 nCol = 0; nCol < nColCount; ++nCol)
+ {
+ String aColTitle = xMeta->getColumnLabel(nCol+1);
+ aColTypes[nCol] = xMeta->getColumnType(nCol+1);
+ maHeader.push_back( mrSharedString.getStringId(aColTitle) );
+ }
+
+ // Initialize field entries container.
+ maFieldEntries.clear();
+ maFieldEntries.reserve(nColCount);
+ for (SCCOL nCol = 0; nCol < nColCount; ++nCol)
+ {
+ TypedScStrCollectionPtr p(new TypedScStrCollection);
+ maFieldEntries.push_back(p);
+ }
+
+ // Now get the data rows.
+ Reference<sdbc::XRow> xRow(xRowSet, UNO_QUERY_THROW);
+ xRowSet->first();
+ maTable.clear();
+ maRowsVisible.clear();
+ do
+ {
+ maRowsVisible.push_back(true);
+ maTable.push_back( vector<Cell>() );
+ maTable.back().reserve(nColCount);
+ for (sal_Int32 nCol = 0; nCol < nColCount; ++nCol)
+ {
+ maTable.back().push_back( Cell() );
+ Cell& rCell = maTable.back().back();
+ ScDPCacheCell aCellContent;
+ String aStr;
+ lcl_GetCellValue(xRow, aColTypes[nCol], nCol+1, rNullDate, aCellContent, aStr, mrSharedString);
+ rCell.mpContent = mpCollection->getCacheCellFromPool(aCellContent);
+
+ TypedStrData* pNew;
+ if (rCell.mpContent->mbNumeric)
+ pNew = new TypedStrData(aStr, rCell.mpContent->mfValue, SC_STRTYPE_VALUE);
+ else
+ pNew = new TypedStrData(aStr);
+
+ if (!maFieldEntries[nCol]->Insert(pNew))
+ delete pNew;
+ }
+ }
+ while (xRowSet->next());
+
+ xRowSet->beforeFirst();
+ }
+ catch (const Exception&)
+ {
+ }
+}
+
+bool ScDPCacheTable::isRowActive(sal_Int32 nRow) const
+{
+ if (nRow < 0 || static_cast<size_t>(nRow) >= maRowsVisible.size())
+ // row index out of bound
+ return false;
+
+ return maRowsVisible[nRow];
+}
+
+void ScDPCacheTable::filterByPageDimension(const vector<Criterion>& rCriteria, const hash_set<sal_Int32>& rRepeatIfEmptyDims)
+{
+ sal_Int32 nRowSize = getRowSize();
+ if (nRowSize != static_cast<sal_Int32>(maRowsVisible.size()))
+ {
+ // sizes of the two tables differ!
+ return;
+ }
+
+ for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
+ maRowsVisible[nRow] = isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims);
+}
+
+const ScDPCacheCell* ScDPCacheTable::getCell(SCCOL nCol, SCROW nRow, bool bRepeatIfEmpty) const
+{
+ if ( nRow >= static_cast<SCROW>(maTable.size()) )
+ return NULL;
+
+ const vector<Cell>& rRow = maTable[nRow];
+ if ( nCol < 0 || static_cast<size_t>(nCol) >= rRow.size() )
+ return NULL;
+
+ const Cell& rCell = rRow[nCol];
+ const ScDPCacheCell* pCell = rCell.mpContent;
+ if (bRepeatIfEmpty && !pCell)
+ pCell = getCell(nCol, rCell.mnCategoryRef, false);
+
+ return pCell ? pCell : &EmptyCellContent;
+}
+
+const String* ScDPCacheTable::getFieldName(sal_Int32 nIndex) const
+{
+ if (nIndex >= static_cast<sal_Int32>(maHeader.size()))
+ return NULL;
+
+ return mrSharedString.getString(maHeader[nIndex]);
+}
+
+sal_Int32 ScDPCacheTable::getFieldIndex(const String& rStr) const
+{
+ sal_Int32 nStrId = mrSharedString.getStringId(rStr);
+ if (nStrId < 0)
+ // string not found.
+ return nStrId;
+
+ sal_Int32 n = maHeader.size();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ if (maHeader[i] == nStrId)
+ return i;
+ }
+
+ return -1;
+}
+
+const TypedScStrCollection& ScDPCacheTable::getFieldEntries(sal_Int32 nIndex) const
+{
+ if (nIndex < 0 || static_cast<size_t>(nIndex) >= maFieldEntries.size())
+ {
+ // index out of bound. Hopefully this code will never be reached.
+ static const TypedScStrCollection emptyCollection;
+ return emptyCollection;
+ }
+
+ return *maFieldEntries[nIndex].get();
+}
+
+void ScDPCacheTable::filterTable(const vector<Criterion>& rCriteria, Sequence< Sequence<Any> >& rTabData,
+ const hash_set<sal_Int32>& rRepeatIfEmptyDims)
+{
+ sal_Int32 nRowSize = getRowSize();
+ sal_Int32 nColSize = getColSize();
+
+ if (!nRowSize)
+ // no data to filter.
+ return;
+
+ // Row first, then column.
+ vector< Sequence<Any> > tableData;
+ tableData.reserve(nRowSize+1);
+
+ // Header first.
+ Sequence<Any> headerRow(nColSize);
+ for (sal_Int32 nCol = 0; nCol < nColSize; ++nCol)
+ {
+ OUString str;
+ const String* pStr = mrSharedString.getString(maHeader[nCol]);
+ if (pStr)
+ str = *pStr;
+
+ Any any;
+ any <<= str;
+ headerRow[nCol] = any;
+ }
+ tableData.push_back(headerRow);
+
+
+ for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
+ {
+ if (!maRowsVisible[nRow])
+ // This row is filtered out.
+ continue;
+
+ if (!isRowQualified(nRow, rCriteria, rRepeatIfEmptyDims))
+ continue;
+
+ // Insert this row into table.
+
+ Sequence<Any> row(nColSize);
+ for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
+ {
+ Any any;
+ bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(nCol) > 0;
+ const ScDPCacheCell* pCell = getCell(nCol, nRow, bRepeatIfEmpty);
+ if (!pCell)
+ {
+ // This should never happen, but in case this happens, just
+ // stick in an empty string.
+ OUString str;
+ any <<= str;
+ row[nCol] = any;
+ continue;
+ }
+
+ if (pCell->mbNumeric)
+ any <<= pCell->mfValue;
+ else
+ {
+ OUString str;
+ const String* pStr = mrSharedString.getString(pCell->mnStrId);
+ if (pStr)
+ str = *pStr;
+ any <<= str;
+ }
+ row[nCol] = any;
+ }
+ tableData.push_back(row);
+ }
+
+ // convert vector to Seqeunce
+ sal_Int32 nTabSize = static_cast<sal_Int32>(tableData.size());
+ rTabData.realloc(nTabSize);
+ for (sal_Int32 i = 0; i < nTabSize; ++i)
+ rTabData[i] = tableData[i];
+}
+
+void ScDPCacheTable::clear()
+{
+ maTable.clear();
+ maHeader.clear();
+ maFieldEntries.clear();
+ maRowsVisible.clear();
+}
+
+void ScDPCacheTable::swap(ScDPCacheTable& rOther)
+{
+ maTable.swap(rOther.maTable);
+ maHeader.swap(rOther.maHeader);
+ maFieldEntries.swap(rOther.maFieldEntries);
+ maRowsVisible.swap(rOther.maRowsVisible);
+}
+
+bool ScDPCacheTable::empty() const
+{
+ return maTable.empty();
+}
+
+bool ScDPCacheTable::isRowQualified(sal_Int32 nRow, const vector<Criterion>& rCriteria,
+ const hash_set<sal_Int32>& rRepeatIfEmptyDims) const
+{
+ sal_Int32 nColSize = getColSize();
+ vector<Criterion>::const_iterator itrEnd = rCriteria.end();
+ for (vector<Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
+ {
+ if (itr->mnFieldIndex >= nColSize)
+ // specified field is outside the source data columns. Don't
+ // use this criterion.
+ continue;
+
+ // Check if the 'repeat if empty' flag is set for this field.
+ bool bRepeatIfEmpty = rRepeatIfEmptyDims.count(itr->mnFieldIndex) > 0;
+ const ScDPCacheCell* pCell = getCell(static_cast<SCCOL>(itr->mnFieldIndex), nRow, bRepeatIfEmpty);
+ if (!pCell)
+ // This should never happen, but just in case...
+ return false;
+
+ if (!itr->mpFilter->match(*pCell))
+ return false;
+ }
+ return true;
+}
+
+void ScDPCacheTable::getValueData(ScDocument* pDoc, const ScAddress& rPos, ScDPCacheCell& rCell)
+{
+ ScBaseCell* pCell = pDoc->GetCell(rPos);
+ if (!pCell)
+ {
+ rCell.mnType = SC_VALTYPE_EMPTY;
+ return;
+ }
+
+ CellType eType = pCell->GetCellType();
+ if (eType == CELLTYPE_NOTE)
+ {
+ // note cell
+ rCell.mnType = SC_VALTYPE_EMPTY;
+ return;
+ }
+
+ if (eType == CELLTYPE_FORMULA && static_cast<ScFormulaCell*>(pCell)->GetErrCode())
+ {
+ // formula cell with error
+ rCell.mnType = SC_VALTYPE_ERROR;
+ return;
+ }
+
+ if ( pCell->HasValueData() )
+ {
+ if (eType == CELLTYPE_VALUE)
+ // value cell
+ rCell.mfValue = static_cast<ScValueCell*>(pCell)->GetValue();
+ else if (eType == CELLTYPE_FORMULA)
+ // formula cell
+ rCell.mfValue = static_cast<ScFormulaCell*>(pCell)->GetValue();
+
+ rCell.mbNumeric = true;
+ rCell.mnType = SC_VALTYPE_VALUE;
+ }
+}
+
diff --git a/sc/source/core/data/dpdimsave.cxx b/sc/source/core/data/dpdimsave.cxx
new file mode 100644
index 000000000000..7e1bc0389eaf
--- /dev/null
+++ b/sc/source/core/data/dpdimsave.cxx
@@ -0,0 +1,587 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dpdimsave.cxx,v $
+ * $Revision: 1.7 $
+ *
+ * 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 "dpdimsave.hxx"
+#include "dpgroup.hxx"
+#include "dpobject.hxx"
+#include "document.hxx"
+
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+
+#include <svtools/zforlist.hxx>
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+#include <algorithm>
+
+// ============================================================================
+
+ScDPSaveGroupItem::ScDPSaveGroupItem( const String& rName ) :
+ aGroupName( rName )
+{
+}
+
+ScDPSaveGroupItem::~ScDPSaveGroupItem()
+{
+}
+
+void ScDPSaveGroupItem::AddElement( const String& rName )
+{
+ aElements.push_back( rName );
+}
+
+void ScDPSaveGroupItem::AddElementsFromGroup( const ScDPSaveGroupItem& rGroup )
+{
+ // add all elements of the other group (used for nested grouping)
+
+ for ( std::vector<String>::const_iterator aIter(rGroup.aElements.begin());
+ aIter != rGroup.aElements.end(); aIter++ )
+ aElements.push_back( *aIter );
+}
+
+bool ScDPSaveGroupItem::RemoveElement( const String& rName )
+{
+ for ( std::vector<String>::iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
+ if ( *aIter == rName ) //! ignore case
+ {
+ aElements.erase( aIter ); // found -> remove
+ return true; // don't have to look further
+ }
+
+ return false; // not found
+}
+
+bool ScDPSaveGroupItem::IsEmpty() const
+{
+ return aElements.empty();
+}
+
+size_t ScDPSaveGroupItem::GetElementCount() const
+{
+ return aElements.size();
+}
+
+const String* ScDPSaveGroupItem::GetElementByIndex( size_t nIndex ) const
+{
+ return (nIndex < aElements.size()) ? &aElements[ nIndex ] : 0;
+}
+
+void ScDPSaveGroupItem::Rename( const String& rNewName )
+{
+ aGroupName = rNewName;
+}
+
+void ScDPSaveGroupItem::RemoveElementsFromGroups( ScDPSaveGroupDimension& rDimension ) const
+{
+ // remove this group's elements from their groups in rDimension
+ // (rDimension must be a different dimension from the one which contains this)
+
+ for ( std::vector<String>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
+ rDimension.RemoveFromGroups( *aIter );
+}
+
+void ScDPSaveGroupItem::AddToData( ScDPGroupDimension& rDataDim, SvNumberFormatter* pFormatter ) const
+{
+ ScDPGroupItem aGroup( aGroupName );
+ ScDPItemData aData;
+
+ for ( std::vector<String>::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
+ {
+ sal_uInt32 nFormat = 0; //! ...
+ double fValue;
+ if ( pFormatter->IsNumberFormat( *aIter, nFormat, fValue ) )
+ aData = ScDPItemData( *aIter, fValue, TRUE );
+ else
+ aData.SetString( *aIter );
+
+ aGroup.AddElement( aData );
+ //! for numeric data, look at source members?
+ }
+
+ rDataDim.AddItem( aGroup );
+}
+
+// ============================================================================
+
+ScDPSaveGroupDimension::ScDPSaveGroupDimension( const String& rSource, const String& rName ) :
+ aSourceDim( rSource ),
+ aGroupDimName( rName ),
+ nDatePart( 0 )
+{
+}
+
+ScDPSaveGroupDimension::ScDPSaveGroupDimension( const String& rSource, const String& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
+ aSourceDim( rSource ),
+ aGroupDimName( rName ),
+ aDateInfo( rDateInfo ),
+ nDatePart( nPart )
+{
+}
+
+ScDPSaveGroupDimension::~ScDPSaveGroupDimension()
+{
+}
+
+void ScDPSaveGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
+{
+ aDateInfo = rInfo;
+ nDatePart = nPart;
+}
+
+void ScDPSaveGroupDimension::AddGroupItem( const ScDPSaveGroupItem& rItem )
+{
+ aGroups.push_back( rItem );
+}
+
+String ScDPSaveGroupDimension::CreateGroupName( const String& rPrefix )
+{
+ // create a name for a new group, using "Group1", "Group2" etc. (translated prefix in rPrefix)
+
+ //! look in all dimensions, to avoid clashes with automatic groups (=name of base element)?
+ //! (only dimensions for the same base)
+
+ sal_Int32 nAdd = 1; // first try is "Group1"
+ const sal_Int32 nMaxAdd = nAdd + aGroups.size(); // limit the loop
+ while ( nAdd <= nMaxAdd )
+ {
+ String aGroupName( rPrefix );
+ aGroupName.Append( String::CreateFromInt32( nAdd ) );
+ bool bExists = false;
+
+ // look for existing groups
+ for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin());
+ aIter != aGroups.end() && !bExists; aIter++ )
+ if ( aIter->GetGroupName() == aGroupName ) //! ignore case
+ bExists = true;
+
+ if ( !bExists )
+ return aGroupName; // found a new name
+
+ ++nAdd; // continue with higher number
+ }
+
+ DBG_ERROR("CreateGroupName: no valid name found");
+ return EMPTY_STRING;
+}
+
+const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroup( const String& rGroupName ) const
+{
+ return const_cast< ScDPSaveGroupDimension* >( this )->GetNamedGroupAcc( rGroupName );
+}
+
+ScDPSaveGroupItem* ScDPSaveGroupDimension::GetNamedGroupAcc( const String& rGroupName )
+{
+ for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
+ if ( aIter->GetGroupName() == rGroupName ) //! ignore case
+ return &*aIter;
+
+ return NULL; // none found
+}
+
+long ScDPSaveGroupDimension::GetGroupCount() const
+{
+ return aGroups.size();
+}
+
+const ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupByIndex( long nIndex ) const
+{
+ return const_cast< ScDPSaveGroupDimension* >( this )->GetGroupAccByIndex( nIndex );
+}
+
+ScDPSaveGroupItem* ScDPSaveGroupDimension::GetGroupAccByIndex( long nIndex )
+{
+ return &aGroups[nIndex];
+}
+
+void ScDPSaveGroupDimension::RemoveFromGroups( const String& rItemName )
+{
+ // if the item is in any group, remove it from the group,
+ // also remove the group if it is empty afterwards
+
+ for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
+ if ( aIter->RemoveElement( rItemName ) )
+ {
+ if ( aIter->IsEmpty() ) // removed last item from the group?
+ aGroups.erase( aIter ); // then remove the group
+
+ return; // don't have to look further
+ }
+}
+
+void ScDPSaveGroupDimension::RemoveGroup( const String& rGroupName )
+{
+ for ( ScDPSaveGroupItemVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
+ if ( aIter->GetGroupName() == rGroupName ) //! ignore case
+ {
+ aGroups.erase( aIter );
+ return; // don't have to look further
+ }
+}
+
+bool ScDPSaveGroupDimension::IsEmpty() const
+{
+ return aGroups.empty();
+}
+
+bool ScDPSaveGroupDimension::HasOnlyHidden( const ScStrCollection& rVisible )
+{
+ // check if there are only groups that don't appear in the list of visible names
+
+ bool bAllHidden = true;
+ for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end() && bAllHidden; aIter++ )
+ {
+ StrData aSearch( aIter->GetGroupName() );
+ USHORT nCollIndex;
+ if ( rVisible.Search( &aSearch, nCollIndex ) )
+ bAllHidden = false; // found one that is visible
+ }
+ return bAllHidden;
+}
+
+void ScDPSaveGroupDimension::Rename( const String& rNewName )
+{
+ aGroupDimName = rNewName;
+}
+
+void ScDPSaveGroupDimension::AddToData( ScDPGroupTableData& rData ) const
+{
+ long nSourceIndex = rData.GetDimensionIndex( aSourceDim );
+ if ( nSourceIndex >= 0 )
+ {
+ ScDPGroupDimension aDim( nSourceIndex, aGroupDimName );
+ if ( nDatePart )
+ {
+ // date grouping
+
+ aDim.MakeDateHelper( aDateInfo, nDatePart );
+ }
+ else
+ {
+ // normal (manual) grouping
+
+ SvNumberFormatter* pFormatter = rData.GetDocument()->GetFormatTable();
+
+ for ( ScDPSaveGroupItemVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
+ aIter->AddToData( aDim, pFormatter );
+ }
+
+ rData.AddGroupDimension( aDim );
+ }
+}
+
+// ============================================================================
+
+ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const String& rName, const ScDPNumGroupInfo& rInfo ) :
+ aDimensionName( rName ),
+ aGroupInfo( rInfo ),
+ nDatePart( 0 )
+{
+}
+
+ScDPSaveNumGroupDimension::ScDPSaveNumGroupDimension( const String& rName, const ScDPNumGroupInfo& rDateInfo, sal_Int32 nPart ) :
+ aDimensionName( rName ),
+ aDateInfo( rDateInfo ),
+ nDatePart( nPart )
+{
+}
+
+ScDPSaveNumGroupDimension::~ScDPSaveNumGroupDimension()
+{
+}
+
+void ScDPSaveNumGroupDimension::AddToData( ScDPGroupTableData& rData ) const
+{
+ long nSource = rData.GetDimensionIndex( aDimensionName );
+ if ( nSource >= 0 )
+ {
+ ScDPNumGroupDimension aDim( aGroupInfo ); // aGroupInfo: value grouping
+ if ( nDatePart )
+ aDim.MakeDateHelper( aDateInfo, nDatePart ); // date grouping
+
+ rData.SetNumGroupDimension( nSource, aDim );
+ }
+}
+
+void ScDPSaveNumGroupDimension::SetGroupInfo( const ScDPNumGroupInfo& rNew )
+{
+ aGroupInfo = rNew;
+}
+
+void ScDPSaveNumGroupDimension::SetDateInfo( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
+{
+ aDateInfo = rInfo;
+ nDatePart = nPart;
+}
+
+// ============================================================================
+
+namespace {
+
+struct ScDPSaveGroupDimNameFunc
+{
+ String maDimName;
+ inline explicit ScDPSaveGroupDimNameFunc( const String& rDimName ) : maDimName( rDimName ) {}
+ inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetGroupDimName() == maDimName; }
+};
+
+struct ScDPSaveGroupSourceNameFunc
+{
+ String maSrcDimName;
+ inline explicit ScDPSaveGroupSourceNameFunc( const String& rSrcDimName ) : maSrcDimName( rSrcDimName ) {}
+ inline bool operator()( const ScDPSaveGroupDimension& rGroupDim ) const { return rGroupDim.GetSourceDimName() == maSrcDimName; }
+};
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+ScDPDimensionSaveData::ScDPDimensionSaveData()
+{
+}
+
+ScDPDimensionSaveData::~ScDPDimensionSaveData()
+{
+}
+
+bool ScDPDimensionSaveData::operator==( const ScDPDimensionSaveData& ) const
+{
+ return false;
+}
+
+void ScDPDimensionSaveData::AddGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
+{
+ DBG_ASSERT( ::std::find_if( maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) ) == maGroupDims.end(),
+ "ScDPDimensionSaveData::AddGroupDimension - group dimension exists already" );
+ // ReplaceGroupDimension() adds new or replaces existing
+ ReplaceGroupDimension( rGroupDim );
+}
+
+void ScDPDimensionSaveData::ReplaceGroupDimension( const ScDPSaveGroupDimension& rGroupDim )
+{
+ ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
+ maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDim.GetGroupDimName() ) );
+ if( aIt == maGroupDims.end() )
+ maGroupDims.push_back( rGroupDim );
+ else
+ *aIt = rGroupDim;
+}
+
+void ScDPDimensionSaveData::RemoveGroupDimension( const String& rGroupDimName )
+{
+ ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
+ maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
+ if( aIt != maGroupDims.end() )
+ maGroupDims.erase( aIt );
+}
+
+void ScDPDimensionSaveData::AddNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
+{
+ DBG_ASSERT( maNumGroupDims.count( rGroupDim.GetDimensionName() ) == 0,
+ "ScDPDimensionSaveData::AddNumGroupDimension - numeric group dimension exists already" );
+ // ReplaceNumGroupDimension() adds new or replaces existing
+ ReplaceNumGroupDimension( rGroupDim );
+}
+
+void ScDPDimensionSaveData::ReplaceNumGroupDimension( const ScDPSaveNumGroupDimension& rGroupDim )
+{
+ ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDim.GetDimensionName() );
+ if( aIt == maNumGroupDims.end() )
+ maNumGroupDims.insert( ScDPSaveNumGroupDimMap::value_type( rGroupDim.GetDimensionName(), rGroupDim ) );
+ else
+ aIt->second = rGroupDim;
+}
+
+void ScDPDimensionSaveData::RemoveNumGroupDimension( const String& rGroupDimName )
+{
+ maNumGroupDims.erase( rGroupDimName );
+}
+
+void ScDPDimensionSaveData::WriteToData( ScDPGroupTableData& rData ) const
+{
+ // rData is assumed to be empty
+ // AddToData also handles date grouping
+
+ for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); aIt != aEnd; ++aIt )
+ aIt->AddToData( rData );
+
+ for( ScDPSaveNumGroupDimMap::const_iterator aIt = maNumGroupDims.begin(), aEnd = maNumGroupDims.end(); aIt != aEnd; ++aIt )
+ aIt->second.AddToData( rData );
+}
+
+const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimForBase( const String& rBaseDimName ) const
+{
+ return const_cast< ScDPDimensionSaveData* >( this )->GetGroupDimAccForBase( rBaseDimName );
+}
+
+const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDim( const String& rGroupDimName ) const
+{
+ return const_cast< ScDPDimensionSaveData* >( this )->GetNamedGroupDimAcc( rGroupDimName );
+}
+
+const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDim( const String& rBaseDimName ) const
+{
+ return const_cast< ScDPDimensionSaveData* >( this )->GetFirstNamedGroupDimAcc( rBaseDimName );
+}
+
+const ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDim( const String& rGroupDimName ) const
+{
+ return const_cast< ScDPDimensionSaveData* >( this )->GetNextNamedGroupDimAcc( rGroupDimName );
+}
+
+const ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDim( const String& rGroupDimName ) const
+{
+ return const_cast< ScDPDimensionSaveData* >( this )->GetNumGroupDimAcc( rGroupDimName );
+}
+
+ScDPSaveGroupDimension* ScDPDimensionSaveData::GetGroupDimAccForBase( const String& rBaseDimName )
+{
+ ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDimAcc( rBaseDimName );
+ return pGroupDim ? pGroupDim : GetNextNamedGroupDimAcc( rBaseDimName );
+}
+
+ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNamedGroupDimAcc( const String& rGroupDimName )
+{
+ ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
+ maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
+ return (aIt == maGroupDims.end()) ? 0 : &*aIt;
+}
+
+ScDPSaveGroupDimension* ScDPDimensionSaveData::GetFirstNamedGroupDimAcc( const String& rBaseDimName )
+{
+ ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
+ maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupSourceNameFunc( rBaseDimName ) );
+ return (aIt == maGroupDims.end()) ? 0 : &*aIt;
+}
+
+ScDPSaveGroupDimension* ScDPDimensionSaveData::GetNextNamedGroupDimAcc( const String& rGroupDimName )
+{
+ // find the group dimension with the passed name
+ ScDPSaveGroupDimVec::iterator aIt = ::std::find_if(
+ maGroupDims.begin(), maGroupDims.end(), ScDPSaveGroupDimNameFunc( rGroupDimName ) );
+ // find next group dimension based on the same source dimension name
+ if( aIt != maGroupDims.end() )
+ aIt = ::std::find_if( aIt + 1, maGroupDims.end(), ScDPSaveGroupSourceNameFunc( aIt->GetSourceDimName() ) );
+ return (aIt == maGroupDims.end()) ? 0 : &*aIt;
+}
+
+ScDPSaveNumGroupDimension* ScDPDimensionSaveData::GetNumGroupDimAcc( const String& rGroupDimName )
+{
+ ScDPSaveNumGroupDimMap::iterator aIt = maNumGroupDims.find( rGroupDimName );
+ return (aIt == maNumGroupDims.end()) ? 0 : &aIt->second;
+}
+
+bool ScDPDimensionSaveData::HasGroupDimensions() const
+{
+ return !maGroupDims.empty() || !maNumGroupDims.empty();
+}
+
+sal_Int32 ScDPDimensionSaveData::CollectDateParts( const String& rBaseDimName ) const
+{
+ sal_Int32 nParts = 0;
+ // start with part of numeric group
+ if( const ScDPSaveNumGroupDimension* pNumDim = GetNumGroupDim( rBaseDimName ) )
+ nParts |= pNumDim->GetDatePart();
+ // collect parts from all matching group dimensions
+ for( const ScDPSaveGroupDimension* pGroupDim = GetFirstNamedGroupDim( rBaseDimName ); pGroupDim; pGroupDim = GetNextNamedGroupDim( pGroupDim->GetGroupDimName() ) )
+ nParts |= pGroupDim->GetDatePart();
+
+ return nParts;
+}
+
+String ScDPDimensionSaveData::CreateGroupDimName( const String& rSourceName,
+ const ScDPObject& rObject, bool bAllowSource,
+ const std::vector<String>* pDeletedNames )
+{
+ // create a name for the new dimension by appending a number to the original
+ // dimension's name
+
+ bool bUseSource = bAllowSource; // if set, try the unchanged original name first
+
+ sal_Int32 nAdd = 2; // first try is "Name2"
+ const sal_Int32 nMaxAdd = 1000; // limit the loop
+ while ( nAdd <= nMaxAdd )
+ {
+ String aDimName( rSourceName );
+ if ( !bUseSource )
+ aDimName.Append( String::CreateFromInt32( nAdd ) );
+ bool bExists = false;
+
+ // look for existing group dimensions
+ for( ScDPSaveGroupDimVec::const_iterator aIt = maGroupDims.begin(), aEnd = maGroupDims.end(); (aIt != aEnd) && !bExists; ++aIt )
+ if( aIt->GetGroupDimName() == aDimName ) //! ignore case
+ bExists = true;
+
+ // look for base dimensions that happen to have that name
+ if ( !bExists && rObject.IsDimNameInUse( aDimName ) )
+ {
+ if ( pDeletedNames &&
+ std::find( pDeletedNames->begin(), pDeletedNames->end(), aDimName ) != pDeletedNames->end() )
+ {
+ // allow the name anyway if the name is in pDeletedNames
+ }
+ else
+ bExists = true;
+ }
+
+ if ( !bExists )
+ return aDimName; // found a new name
+
+ if ( bUseSource )
+ bUseSource = false;
+ else
+ ++nAdd; // continue with higher number
+ }
+ DBG_ERROR("CreateGroupDimName: no valid name found");
+ return EMPTY_STRING;
+}
+
+String ScDPDimensionSaveData::CreateDateGroupDimName( sal_Int32 nDatePart, const ScDPObject& rObject, bool bAllowSource, const ::std::vector< String >* pDeletedNames )
+{
+ using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
+ String aPartName;
+ switch( nDatePart )
+ {
+ //! use translated strings from globstr.src
+ case SECONDS: aPartName = String::CreateFromAscii( "Seconds" ); break;
+ case MINUTES: aPartName = String::CreateFromAscii( "Minutes" ); break;
+ case HOURS: aPartName = String::CreateFromAscii( "Hours" ); break;
+ case DAYS: aPartName = String::CreateFromAscii( "Days" ); break;
+ case MONTHS: aPartName = String::CreateFromAscii( "Months" ); break;
+ case QUARTERS: aPartName = String::CreateFromAscii( "Quarters" ); break;
+ case YEARS: aPartName = String::CreateFromAscii( "Years" ); break;
+ }
+ DBG_ASSERT( aPartName.Len() > 0, "ScDPDimensionSaveData::CreateDateGroupDimName - invalid date part" );
+ return CreateGroupDimName( aPartName, rObject, bAllowSource, pDeletedNames );
+}
+
+// ============================================================================
+
diff --git a/sc/source/core/data/dpgroup.cxx b/sc/source/core/data/dpgroup.cxx
new file mode 100644
index 000000000000..a92d1681ec0e
--- /dev/null
+++ b/sc/source/core/data/dpgroup.cxx
@@ -0,0 +1,1534 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dpgroup.cxx,v $
+ * $Revision: 1.11 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
+
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <svtools/zforlist.hxx>
+
+#include "dpgroup.hxx"
+#include "collect.hxx"
+#include "global.hxx"
+#include "document.hxx"
+#include "dpcachetable.hxx"
+#include "dptabsrc.hxx"
+#include "dptabres.hxx"
+#include "dpobject.hxx"
+
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+
+#include <vector>
+#include <hash_set>
+#include <hash_map>
+
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::rtl::OUString;
+using ::rtl::OUStringHash;
+
+using ::std::vector;
+using ::std::hash_set;
+using ::std::hash_map;
+
+#define D_TIMEFACTOR 86400.0
+
+const USHORT SC_DP_LEAPYEAR = 1648; // arbitrary leap year for date calculations
+
+// part values for the extra "<" and ">" entries (same for all parts)
+const sal_Int32 SC_DP_DATE_FIRST = -1;
+const sal_Int32 SC_DP_DATE_LAST = 10000;
+
+// ============================================================================
+
+class ScDPGroupDateFilter : public ScDPCacheTable::FilterBase
+{
+public:
+ ScDPGroupDateFilter(double fMatchValue, sal_Int32 nDatePart,
+ const Date* pNullDate, const ScDPNumGroupInfo* pNumInfo);
+
+ virtual bool match(const ScDPCacheCell &rCell) const;
+
+private:
+ ScDPGroupDateFilter(); // disabled
+
+ const Date* mpNullDate;
+ const ScDPNumGroupInfo* mpNumInfo;
+ double mfMatchValue;
+ sal_Int32 mnDatePart;
+};
+
+// ----------------------------------------------------------------------------
+
+ScDPGroupDateFilter::ScDPGroupDateFilter(double fMatchValue, sal_Int32 nDatePart,
+ const Date* pNullDate, const ScDPNumGroupInfo* pNumInfo) :
+ mpNullDate(pNullDate),
+ mpNumInfo(pNumInfo),
+ mfMatchValue(fMatchValue),
+ mnDatePart(nDatePart)
+{
+// fprintf(stdout, "ScDPCacheTable:DateGroupFilter::DateGroupFilter: match value = %g; date part = %ld\n",
+// mfMatchValue, mnDatePart);
+}
+
+bool ScDPGroupDateFilter::match(const ScDPCacheCell& rCell) const
+{
+ using namespace ::com::sun::star::sheet;
+ using ::rtl::math::approxFloor;
+ using ::rtl::math::approxEqual;
+
+ if (!rCell.mbNumeric)
+ return false;
+
+ if (!mpNumInfo)
+ return false;
+
+ // Start and end dates are inclusive. (An end date without a time value
+ // is included, while an end date with a time value is not.)
+
+ if ( rCell.mfValue < mpNumInfo->Start && !approxEqual(rCell.mfValue, mpNumInfo->Start) )
+ return static_cast<sal_Int32>(mfMatchValue) == SC_DP_DATE_FIRST;
+
+ if ( rCell.mfValue > mpNumInfo->End && !approxEqual(rCell.mfValue, mpNumInfo->End) )
+ return static_cast<sal_Int32>(mfMatchValue) == SC_DP_DATE_LAST;
+
+ if (mnDatePart == DataPilotFieldGroupBy::HOURS || mnDatePart == DataPilotFieldGroupBy::MINUTES ||
+ mnDatePart == DataPilotFieldGroupBy::SECONDS)
+ {
+ // handle time
+ // (as in the cell functions, ScInterpreter::ScGetHour etc.: seconds are rounded)
+
+ double time = rCell.mfValue - approxFloor(rCell.mfValue);
+ long seconds = static_cast<long>(approxFloor(time*D_TIMEFACTOR + 0.5));
+
+ switch (mnDatePart)
+ {
+ case DataPilotFieldGroupBy::HOURS:
+ {
+ sal_Int32 hrs = seconds / 3600;
+ sal_Int32 matchHrs = static_cast<sal_Int32>(mfMatchValue);
+ return hrs == matchHrs;
+ }
+ case DataPilotFieldGroupBy::MINUTES:
+ {
+ sal_Int32 minutes = (seconds % 3600) / 60;
+ sal_Int32 matchMinutes = static_cast<sal_Int32>(mfMatchValue);
+ return minutes == matchMinutes;
+ }
+ case DataPilotFieldGroupBy::SECONDS:
+ {
+ sal_Int32 sec = seconds % 60;
+ sal_Int32 matchSec = static_cast<sal_Int32>(mfMatchValue);
+ return sec == matchSec;
+ }
+ default:
+ DBG_ERROR("invalid time part");
+ }
+ return false;
+ }
+
+ Date date = *mpNullDate + static_cast<long>(approxFloor(rCell.mfValue));
+ switch (mnDatePart)
+ {
+ case DataPilotFieldGroupBy::YEARS:
+ {
+ sal_Int32 year = static_cast<sal_Int32>(date.GetYear());
+ sal_Int32 matchYear = static_cast<sal_Int32>(mfMatchValue);
+ return year == matchYear;
+ }
+ case DataPilotFieldGroupBy::QUARTERS:
+ {
+ sal_Int32 qtr = 1 + (static_cast<sal_Int32>(date.GetMonth()) - 1) / 3;
+ sal_Int32 matchQtr = static_cast<sal_Int32>(mfMatchValue);
+ return qtr == matchQtr;
+ }
+ case DataPilotFieldGroupBy::MONTHS:
+ {
+ sal_Int32 month = static_cast<sal_Int32>(date.GetMonth());
+ sal_Int32 matchMonth = static_cast<sal_Int32>(mfMatchValue);
+ return month == matchMonth;
+ }
+ case DataPilotFieldGroupBy::DAYS:
+ {
+ Date yearStart(1, 1, date.GetYear());
+ sal_Int32 days = (date - yearStart) + 1; // Jan 01 has value 1
+ if (days >= 60 && !date.IsLeapYear())
+ {
+ // This is not a leap year. Adjust the value accordingly.
+ ++days;
+ }
+ sal_Int32 matchDays = static_cast<sal_Int32>(mfMatchValue);
+ return days == matchDays;
+ }
+ default:
+ DBG_ERROR("invalid date part");
+ }
+
+ return false;
+}
+
+// ============================================================================
+
+void lcl_AppendDateStr( rtl::OUStringBuffer& rBuffer, double fValue, SvNumberFormatter* pFormatter )
+{
+ ULONG nFormat = pFormatter->GetStandardFormat( NUMBERFORMAT_DATE, ScGlobal::eLnge );
+ String aString;
+ pFormatter->GetInputLineString( fValue, nFormat, aString );
+ rBuffer.append( aString );
+}
+
+// -----------------------------------------------------------------------
+
+ScDPDateGroupHelper::ScDPDateGroupHelper( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart ) :
+ aNumInfo( rInfo ),
+ nDatePart( nPart )
+{
+}
+
+ScDPDateGroupHelper::~ScDPDateGroupHelper()
+{
+}
+
+String lcl_GetTwoDigitString( sal_Int32 nValue )
+{
+ String aRet = String::CreateFromInt32( nValue );
+ if ( aRet.Len() < 2 )
+ aRet.Insert( (sal_Unicode)'0', 0 );
+ return aRet;
+}
+
+String lcl_GetDateGroupName( sal_Int32 nDatePart, sal_Int32 nValue, SvNumberFormatter* pFormatter )
+{
+ String aRet;
+ switch ( nDatePart )
+ {
+ case com::sun::star::sheet::DataPilotFieldGroupBy::YEARS:
+ aRet = String::CreateFromInt32( nValue );
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS:
+ aRet = ScGlobal::pLocaleData->getQuarterAbbreviation( (sal_Int16)(nValue - 1) ); // nValue is 1-based
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:
+ //! cache getMonths() result?
+ aRet = ScGlobal::pCalendar->getDisplayName(
+ ::com::sun::star::i18n::CalendarDisplayIndex::MONTH,
+ sal_Int16(nValue-1), 0 ); // 0-based, get short name
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:
+ {
+ Date aDate( 1, 1, SC_DP_LEAPYEAR );
+ aDate += ( nValue - 1 ); // nValue is 1-based
+ Date aNullDate = *(pFormatter->GetNullDate());
+ long nDays = aDate - aNullDate;
+
+ ULONG nFormat = pFormatter->GetFormatIndex( NF_DATE_SYS_DDMMM, ScGlobal::eLnge );
+ Color* pColor;
+ pFormatter->GetOutputString( nDays, nFormat, aRet, &pColor );
+ }
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::HOURS:
+ //! allow am/pm format?
+ aRet = lcl_GetTwoDigitString( nValue );
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::MINUTES:
+ case com::sun::star::sheet::DataPilotFieldGroupBy::SECONDS:
+ aRet = ScGlobal::pLocaleData->getTimeSep();
+ aRet.Append( lcl_GetTwoDigitString( nValue ) );
+ break;
+ default:
+ DBG_ERROR("invalid date part");
+ }
+ return aRet;
+}
+
+sal_Int32 lcl_GetDatePartValue( double fValue, sal_Int32 nDatePart, SvNumberFormatter* pFormatter,
+ const ScDPNumGroupInfo* pNumInfo )
+{
+ // Start and end are inclusive
+ // (End date without a time value is included, with a time value it's not)
+
+ if ( pNumInfo )
+ {
+ if ( fValue < pNumInfo->Start && !rtl::math::approxEqual( fValue, pNumInfo->Start ) )
+ return SC_DP_DATE_FIRST;
+ if ( fValue > pNumInfo->End && !rtl::math::approxEqual( fValue, pNumInfo->End ) )
+ return SC_DP_DATE_LAST;
+ }
+
+ sal_Int32 nResult = 0;
+
+ if ( nDatePart == com::sun::star::sheet::DataPilotFieldGroupBy::HOURS || nDatePart == com::sun::star::sheet::DataPilotFieldGroupBy::MINUTES || nDatePart == com::sun::star::sheet::DataPilotFieldGroupBy::SECONDS )
+ {
+ // handle time
+ // (as in the cell functions, ScInterpreter::ScGetHour etc.: seconds are rounded)
+
+ double fTime = fValue - ::rtl::math::approxFloor(fValue);
+ long nSeconds = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5);
+
+ switch ( nDatePart )
+ {
+ case com::sun::star::sheet::DataPilotFieldGroupBy::HOURS:
+ nResult = nSeconds / 3600;
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::MINUTES:
+ nResult = ( nSeconds % 3600 ) / 60;
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::SECONDS:
+ nResult = nSeconds % 60;
+ break;
+ }
+ }
+ else
+ {
+ Date aDate = *(pFormatter->GetNullDate());
+ aDate += (long)::rtl::math::approxFloor( fValue );
+
+ switch ( nDatePart )
+ {
+ case com::sun::star::sheet::DataPilotFieldGroupBy::YEARS:
+ nResult = aDate.GetYear();
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS:
+ nResult = 1 + ( aDate.GetMonth() - 1 ) / 3; // 1..4
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:
+ nResult = aDate.GetMonth(); // 1..12
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:
+ {
+ Date aYearStart( 1, 1, aDate.GetYear() );
+ nResult = ( aDate - aYearStart ) + 1; // Jan 01 has value 1
+ if ( nResult >= 60 && !aDate.IsLeapYear() )
+ {
+ // days are counted from 1 to 366 - if not from a leap year, adjust
+ ++nResult;
+ }
+ }
+ break;
+ default:
+ DBG_ERROR("invalid date part");
+ }
+ }
+
+ return nResult;
+}
+
+BOOL lcl_DateContained( sal_Int32 nGroupPart, const ScDPItemData& rGroupData,
+ sal_Int32 nBasePart, const ScDPItemData& rBaseData )
+{
+ if ( !rGroupData.bHasValue || !rBaseData.bHasValue )
+ {
+ // non-numeric entries involved: only match equal entries
+ return rGroupData.IsCaseInsEqual( rBaseData );
+ }
+
+ // no approxFloor needed, values were created from integers
+ sal_Int32 nGroupValue = (sal_Int32) rGroupData.fValue;
+ sal_Int32 nBaseValue = (sal_Int32) rBaseData.fValue;
+ if ( nBasePart > nGroupPart )
+ {
+ // switch, so the base part is the smaller (inner) part
+
+ ::std::swap( nGroupPart, nBasePart );
+ ::std::swap( nGroupValue, nBaseValue );
+ }
+
+ if ( nGroupValue == SC_DP_DATE_FIRST || nGroupValue == SC_DP_DATE_LAST ||
+ nBaseValue == SC_DP_DATE_FIRST || nBaseValue == SC_DP_DATE_LAST )
+ {
+ // first/last entry matches only itself
+ return ( nGroupValue == nBaseValue );
+ }
+
+ BOOL bContained = TRUE;
+ switch ( nBasePart ) // inner part
+ {
+ case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS:
+ // a month is only contained in its quarter
+ if ( nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS )
+ {
+ // months and quarters are both 1-based
+ bContained = ( nGroupValue - 1 == ( nBaseValue - 1 ) / 3 );
+ }
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS:
+ // a day is only contained in its quarter or month
+ if ( nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS || nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS )
+ {
+ Date aDate( 1, 1, SC_DP_LEAPYEAR );
+ aDate += ( nBaseValue - 1 ); // days are 1-based
+ sal_Int32 nCompare = aDate.GetMonth();
+ if ( nGroupPart == com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS )
+ nCompare = ( ( nCompare - 1 ) / 3 ) + 1; // get quarter from date
+
+ bContained = ( nGroupValue == nCompare );
+ }
+ break;
+
+ // other parts: everything is contained
+ }
+
+ return bContained;
+}
+
+String lcl_GetSpecialDateName( double fValue, bool bFirst, SvNumberFormatter* pFormatter )
+{
+ rtl::OUStringBuffer aBuffer;
+ aBuffer.append((sal_Unicode)( bFirst ? '<' : '>' ));
+ lcl_AppendDateStr( aBuffer, fValue, pFormatter );
+ return aBuffer.makeStringAndClear();
+}
+
+void ScDPDateGroupHelper::FillColumnEntries( TypedScStrCollection& rEntries, const TypedScStrCollection& rOriginal,
+ SvNumberFormatter* pFormatter ) const
+{
+ // auto min/max is only used for "Years" part, but the loop is always needed
+ double fSourceMin = 0.0;
+ double fSourceMax = 0.0;
+ bool bFirst = true;
+
+ USHORT nOriginalCount = rOriginal.GetCount();
+ for (USHORT nOriginalPos=0; nOriginalPos<nOriginalCount; nOriginalPos++)
+ {
+ const TypedStrData& rStrData = *rOriginal[nOriginalPos];
+ if ( rStrData.IsStrData() )
+ {
+ // string data: just copy
+ TypedStrData* pNew = new TypedStrData( rStrData );
+ if ( !rEntries.Insert( pNew ) )
+ delete pNew;
+ }
+ else
+ {
+ double fSourceValue = rStrData.GetValue();
+ if ( bFirst )
+ {
+ fSourceMin = fSourceMax = fSourceValue;
+ bFirst = false;
+ }
+ else
+ {
+ if ( fSourceValue < fSourceMin )
+ fSourceMin = fSourceValue;
+ if ( fSourceValue > fSourceMax )
+ fSourceMax = fSourceValue;
+ }
+ }
+ }
+
+ // For the start/end values, use the same date rounding as in ScDPNumGroupDimension::GetNumEntries
+ // (but not for the list of available years):
+ if ( aNumInfo.AutoStart )
+ const_cast<ScDPDateGroupHelper*>(this)->aNumInfo.Start = rtl::math::approxFloor( fSourceMin );
+ if ( aNumInfo.AutoEnd )
+ const_cast<ScDPDateGroupHelper*>(this)->aNumInfo.End = rtl::math::approxFloor( fSourceMax ) + 1;
+
+ //! if not automatic, limit fSourceMin/fSourceMax for list of year values?
+
+ long nStart = 0;
+ long nEnd = 0; // including
+
+ switch ( nDatePart )
+ {
+ case com::sun::star::sheet::DataPilotFieldGroupBy::YEARS:
+ nStart = lcl_GetDatePartValue( fSourceMin, com::sun::star::sheet::DataPilotFieldGroupBy::YEARS, pFormatter, NULL );
+ nEnd = lcl_GetDatePartValue( fSourceMax, com::sun::star::sheet::DataPilotFieldGroupBy::YEARS, pFormatter, NULL );
+ break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::QUARTERS: nStart = 1; nEnd = 4; break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::MONTHS: nStart = 1; nEnd = 12; break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::DAYS: nStart = 1; nEnd = 366; break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::HOURS: nStart = 0; nEnd = 23; break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::MINUTES: nStart = 0; nEnd = 59; break;
+ case com::sun::star::sheet::DataPilotFieldGroupBy::SECONDS: nStart = 0; nEnd = 59; break;
+ default:
+ DBG_ERROR("invalid date part");
+ }
+
+ for ( sal_Int32 nValue = nStart; nValue <= nEnd; nValue++ )
+ {
+ String aName = lcl_GetDateGroupName( nDatePart, nValue, pFormatter );
+ TypedStrData* pNew = new TypedStrData( aName, nValue, SC_STRTYPE_VALUE );
+ if ( !rEntries.Insert( pNew ) )
+ delete pNew;
+ }
+
+ // add first/last entry (min/max)
+
+ String aFirstName = lcl_GetSpecialDateName( aNumInfo.Start, true, pFormatter );
+ TypedStrData* pFirstEntry = new TypedStrData( aFirstName, SC_DP_DATE_FIRST, SC_STRTYPE_VALUE );
+ if ( !rEntries.Insert( pFirstEntry ) )
+ delete pFirstEntry;
+
+ String aLastName = lcl_GetSpecialDateName( aNumInfo.End, false, pFormatter );
+ TypedStrData* pLastEntry = new TypedStrData( aLastName, SC_DP_DATE_LAST, SC_STRTYPE_VALUE );
+ if ( !rEntries.Insert( pLastEntry ) )
+ delete pLastEntry;
+}
+
+// -----------------------------------------------------------------------
+
+ScDPGroupItem::ScDPGroupItem( const ScDPItemData& rName ) :
+ aGroupName( rName )
+{
+}
+
+ScDPGroupItem::~ScDPGroupItem()
+{
+}
+
+void ScDPGroupItem::AddElement( const ScDPItemData& rName )
+{
+ aElements.push_back( rName );
+}
+
+bool ScDPGroupItem::HasElement( const ScDPItemData& rData ) const
+{
+ for ( ScDPItemDataVec::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
+ if ( aIter->IsCaseInsEqual( rData ) )
+ return true;
+
+ return false;
+}
+
+bool ScDPGroupItem::HasCommonElement( const ScDPGroupItem& rOther ) const
+{
+ for ( ScDPItemDataVec::const_iterator aIter(aElements.begin()); aIter != aElements.end(); aIter++ )
+ if ( rOther.HasElement( *aIter ) )
+ return true;
+
+ return false;
+}
+
+void ScDPGroupItem::FillGroupFilter( ScDPCacheTable::GroupFilter& rFilter ) const
+{
+ ScDPItemDataVec::const_iterator itrEnd = aElements.end();
+ for (ScDPItemDataVec::const_iterator itr = aElements.begin(); itr != itrEnd; ++itr)
+ rFilter.addMatchItem(itr->aString, itr->fValue, itr->bHasValue);
+}
+
+// -----------------------------------------------------------------------
+
+ScDPGroupDimension::ScDPGroupDimension( long nSource, const String& rNewName ) :
+ nSourceDim( nSource ),
+ nGroupDim( -1 ),
+ aGroupName( rNewName ),
+ pDateHelper( NULL ),
+ pCollection( NULL )
+{
+}
+
+ScDPGroupDimension::~ScDPGroupDimension()
+{
+ delete pDateHelper;
+ delete pCollection;
+}
+
+ScDPGroupDimension::ScDPGroupDimension( const ScDPGroupDimension& rOther ) :
+ nSourceDim( rOther.nSourceDim ),
+ nGroupDim( rOther.nGroupDim ),
+ aGroupName( rOther.aGroupName ),
+ pDateHelper( NULL ),
+ aItems( rOther.aItems ),
+ pCollection( NULL ) // collection isn't copied - allocated on demand
+{
+ if ( rOther.pDateHelper )
+ pDateHelper = new ScDPDateGroupHelper( *rOther.pDateHelper );
+}
+
+ScDPGroupDimension& ScDPGroupDimension::operator=( const ScDPGroupDimension& rOther )
+{
+ nSourceDim = rOther.nSourceDim;
+ nGroupDim = rOther.nGroupDim;
+ aGroupName = rOther.aGroupName;
+ aItems = rOther.aItems;
+
+ delete pDateHelper;
+ if ( rOther.pDateHelper )
+ pDateHelper = new ScDPDateGroupHelper( *rOther.pDateHelper );
+ else
+ pDateHelper = NULL;
+
+ delete pCollection; // collection isn't copied - allocated on demand
+ pCollection = NULL;
+ return *this;
+}
+
+void ScDPGroupDimension::MakeDateHelper( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
+{
+ delete pDateHelper;
+ pDateHelper = new ScDPDateGroupHelper( rInfo, nPart );
+}
+
+void ScDPGroupDimension::AddItem( const ScDPGroupItem& rItem )
+{
+ aItems.push_back( rItem );
+}
+
+void ScDPGroupDimension::SetGroupDim( long nDim )
+{
+ nGroupDim = nDim;
+}
+
+const TypedScStrCollection& ScDPGroupDimension::GetColumnEntries(
+ const TypedScStrCollection& rOriginal, ScDocument* pDoc ) const
+{
+ if ( !pCollection )
+ {
+ pCollection = new TypedScStrCollection();
+ if ( pDateHelper )
+ pDateHelper->FillColumnEntries( *pCollection, rOriginal, pDoc->GetFormatTable() );
+ else
+ {
+ long nCount = aItems.size();
+ for (long i=0; i<nCount; i++)
+ {
+ //! numeric entries?
+ TypedStrData* pNew = new TypedStrData( aItems[i].GetName().aString );
+ if ( !pCollection->Insert( pNew ) )
+ delete pNew;
+ }
+
+ USHORT nOriginalCount = rOriginal.GetCount();
+ for (USHORT nOriginalPos=0; nOriginalPos<nOriginalCount; nOriginalPos++)
+ {
+ const TypedStrData& rStrData = *rOriginal[nOriginalPos];
+ ScDPItemData aItemData( rStrData.GetString(), rStrData.GetValue(), !rStrData.IsStrData() );
+ if ( !GetGroupForData( aItemData ) )
+ {
+ // not in any group -> add as its own group
+ TypedStrData* pNew = new TypedStrData( rStrData );
+ if ( !pCollection->Insert( pNew ) )
+ delete pNew;
+ }
+ }
+ }
+ }
+ return *pCollection;
+}
+
+const ScDPGroupItem* ScDPGroupDimension::GetGroupForData( const ScDPItemData& rData ) const
+{
+ for ( ScDPGroupItemVec::const_iterator aIter(aItems.begin()); aIter != aItems.end(); aIter++ )
+ if ( aIter->HasElement( rData ) )
+ return &*aIter;
+
+ return NULL;
+}
+
+const ScDPGroupItem* ScDPGroupDimension::GetGroupForName( const ScDPItemData& rName ) const
+{
+ for ( ScDPGroupItemVec::const_iterator aIter(aItems.begin()); aIter != aItems.end(); aIter++ )
+ if ( aIter->GetName().IsCaseInsEqual( rName ) )
+ return &*aIter;
+
+ return NULL;
+}
+
+const ScDPGroupItem* ScDPGroupDimension::GetGroupByIndex( size_t nIndex ) const
+{
+ if (nIndex >= aItems.size())
+ return NULL;
+
+ return &aItems[nIndex];
+}
+
+void ScDPGroupDimension::DisposeData()
+{
+ delete pCollection;
+ pCollection = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ScDPNumGroupDimension::ScDPNumGroupDimension() :
+ pDateHelper( NULL ),
+ pCollection( NULL ),
+ bHasNonInteger( false ),
+ cDecSeparator( 0 )
+{
+}
+
+ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupInfo& rInfo ) :
+ aGroupInfo( rInfo ),
+ pDateHelper( NULL ),
+ pCollection( NULL ),
+ bHasNonInteger( false ),
+ cDecSeparator( 0 )
+{
+}
+
+ScDPNumGroupDimension::ScDPNumGroupDimension( const ScDPNumGroupDimension& rOther ) :
+ aGroupInfo( rOther.aGroupInfo ),
+ pDateHelper( NULL ),
+ pCollection( NULL ), // collection isn't copied - allocated on demand
+ bHasNonInteger( false ),
+ cDecSeparator( 0 )
+{
+ if ( rOther.pDateHelper )
+ pDateHelper = new ScDPDateGroupHelper( *rOther.pDateHelper );
+}
+
+ScDPNumGroupDimension& ScDPNumGroupDimension::operator=( const ScDPNumGroupDimension& rOther )
+{
+ aGroupInfo = rOther.aGroupInfo;
+
+ delete pDateHelper;
+ if ( rOther.pDateHelper )
+ pDateHelper = new ScDPDateGroupHelper( *rOther.pDateHelper );
+ else
+ pDateHelper = NULL;
+
+ delete pCollection; // collection isn't copied - allocated on demand
+ pCollection = NULL;
+ bHasNonInteger = false;
+ return *this;
+}
+
+void ScDPNumGroupDimension::DisposeData()
+{
+ delete pCollection;
+ pCollection = NULL;
+ bHasNonInteger = false;
+}
+
+ScDPNumGroupDimension::~ScDPNumGroupDimension()
+{
+ delete pDateHelper;
+ delete pCollection;
+}
+
+void ScDPNumGroupDimension::MakeDateHelper( const ScDPNumGroupInfo& rInfo, sal_Int32 nPart )
+{
+ delete pDateHelper;
+ pDateHelper = new ScDPDateGroupHelper( rInfo, nPart );
+
+ aGroupInfo.Enable = sal_True; //! or query both?
+}
+
+String lcl_GetNumGroupName( double fStartValue, const ScDPNumGroupInfo& rInfo,
+ bool bHasNonInteger, sal_Unicode cDecSeparator, SvNumberFormatter* pFormatter )
+{
+ DBG_ASSERT( cDecSeparator != 0, "cDecSeparator not initialized" );
+
+ double fStep = rInfo.Step;
+ double fEndValue = fStartValue + fStep;
+ if ( !bHasNonInteger && ( rInfo.DateValues || !rtl::math::approxEqual( fEndValue, rInfo.End ) ) )
+ {
+ // The second number of the group label is
+ // (first number + size - 1) if there are only integer numbers,
+ // (first number + size) if any non-integer numbers are involved.
+ // Exception: The last group (containing the end value) is always
+ // shown as including the end value (but not for dates).
+
+ fEndValue -= 1.0;
+ }
+
+ if ( fEndValue > rInfo.End && !rInfo.AutoEnd )
+ {
+ // limit the last group to the end value
+
+ fEndValue = rInfo.End;
+ }
+
+ rtl::OUStringBuffer aBuffer;
+ if ( rInfo.DateValues )
+ {
+ lcl_AppendDateStr( aBuffer, fStartValue, pFormatter );
+ aBuffer.appendAscii( " - " ); // with spaces
+ lcl_AppendDateStr( aBuffer, fEndValue, pFormatter );
+ }
+ else
+ {
+ rtl::math::doubleToUStringBuffer( aBuffer, fStartValue, rtl_math_StringFormat_Automatic,
+ rtl_math_DecimalPlaces_Max, cDecSeparator, true );
+ aBuffer.append( (sal_Unicode) '-' );
+ rtl::math::doubleToUStringBuffer( aBuffer, fEndValue, rtl_math_StringFormat_Automatic,
+ rtl_math_DecimalPlaces_Max, cDecSeparator, true );
+ }
+
+ return aBuffer.makeStringAndClear();
+}
+
+String lcl_GetSpecialNumGroupName( double fValue, bool bFirst, sal_Unicode cDecSeparator,
+ bool bDateValues, SvNumberFormatter* pFormatter )
+{
+ DBG_ASSERT( cDecSeparator != 0, "cDecSeparator not initialized" );
+
+ rtl::OUStringBuffer aBuffer;
+ aBuffer.append((sal_Unicode)( bFirst ? '<' : '>' ));
+ if ( bDateValues )
+ lcl_AppendDateStr( aBuffer, fValue, pFormatter );
+ else
+ rtl::math::doubleToUStringBuffer( aBuffer, fValue, rtl_math_StringFormat_Automatic,
+ rtl_math_DecimalPlaces_Max, cDecSeparator, true );
+ return aBuffer.makeStringAndClear();
+}
+
+inline bool IsInteger( double fValue )
+{
+ return rtl::math::approxEqual( fValue, rtl::math::approxFloor(fValue) );
+}
+
+const TypedScStrCollection& ScDPNumGroupDimension::GetNumEntries(
+ const TypedScStrCollection& rOriginal, ScDocument* pDoc ) const
+{
+ if ( !pCollection )
+ {
+ SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
+
+ pCollection = new TypedScStrCollection();
+ if ( pDateHelper )
+ pDateHelper->FillColumnEntries( *pCollection, rOriginal, pFormatter );
+ else
+ {
+ // Copy textual entries.
+ // Also look through the source entries for non-integer numbers, minimum and maximum.
+ // GetNumEntries (GetColumnEntries) must be called before accessing the groups
+ // (this in ensured by calling ScDPLevel::GetMembersObject for all column/row/page
+ // dimensions before iterating over the values).
+
+ cDecSeparator = ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0);
+
+ // non-integer GroupInfo values count, too
+ bHasNonInteger = ( !aGroupInfo.AutoStart && !IsInteger( aGroupInfo.Start ) ) ||
+ ( !aGroupInfo.AutoEnd && !IsInteger( aGroupInfo.End ) ) ||
+ !IsInteger( aGroupInfo.Step );
+ double fSourceMin = 0.0;
+ double fSourceMax = 0.0;
+ bool bFirst = true;
+
+ USHORT nOriginalCount = rOriginal.GetCount();
+ for (USHORT nOriginalPos=0; nOriginalPos<nOriginalCount; nOriginalPos++)
+ {
+ const TypedStrData& rStrData = *rOriginal[nOriginalPos];
+ if ( rStrData.IsStrData() )
+ {
+ // string data: just copy
+ TypedStrData* pNew = new TypedStrData( rStrData );
+ if ( !pCollection->Insert( pNew ) )
+ delete pNew;
+ }
+ else
+ {
+ double fSourceValue = rStrData.GetValue();
+ if ( bFirst )
+ {
+ fSourceMin = fSourceMax = fSourceValue;
+ bFirst = false;
+ }
+ else
+ {
+ if ( fSourceValue < fSourceMin )
+ fSourceMin = fSourceValue;
+ if ( fSourceValue > fSourceMax )
+ fSourceMax = fSourceValue;
+ }
+ if ( !bHasNonInteger && !IsInteger( fSourceValue ) )
+ {
+ // if any non-integer numbers are involved, the group labels are
+ // shown including their upper limit
+ bHasNonInteger = true;
+ }
+ }
+ }
+
+ if ( aGroupInfo.DateValues )
+ {
+ // special handling for dates: always integer, round down limits
+ bHasNonInteger = false;
+ fSourceMin = rtl::math::approxFloor( fSourceMin );
+ fSourceMax = rtl::math::approxFloor( fSourceMax ) + 1;
+ }
+
+ if ( aGroupInfo.AutoStart )
+ const_cast<ScDPNumGroupDimension*>(this)->aGroupInfo.Start = fSourceMin;
+ if ( aGroupInfo.AutoEnd )
+ const_cast<ScDPNumGroupDimension*>(this)->aGroupInfo.End = fSourceMax;
+
+ //! limit number of entries?
+
+ long nLoopCount = 0;
+ double fLoop = aGroupInfo.Start;
+
+ // Use "less than" instead of "less or equal" for the loop - don't create a group
+ // that consists only of the end value. Instead, the end value is then included
+ // in the last group (last group is bigger than the others).
+ // The first group has to be created nonetheless. GetNumGroupForValue has corresponding logic.
+
+ bool bFirstGroup = true;
+ while ( bFirstGroup || ( fLoop < aGroupInfo.End && !rtl::math::approxEqual( fLoop, aGroupInfo.End ) ) )
+ {
+ String aName = lcl_GetNumGroupName( fLoop, aGroupInfo, bHasNonInteger, cDecSeparator, pFormatter );
+ // create a numerical entry to ensure proper sorting
+ // (in FillMemberResults this needs special handling)
+ TypedStrData* pNew = new TypedStrData( aName, fLoop, SC_STRTYPE_VALUE );
+ if ( !pCollection->Insert( pNew ) )
+ delete pNew;
+
+ ++nLoopCount;
+ fLoop = aGroupInfo.Start + nLoopCount * aGroupInfo.Step;
+ bFirstGroup = false;
+
+ // ScDPItemData values are compared with approxEqual
+ }
+
+ String aFirstName = lcl_GetSpecialNumGroupName( aGroupInfo.Start, true, cDecSeparator, aGroupInfo.DateValues, pFormatter );
+ TypedStrData* pFirstEntry = new TypedStrData( aFirstName, aGroupInfo.Start - aGroupInfo.Step, SC_STRTYPE_VALUE );
+ if ( !pCollection->Insert( pFirstEntry ) )
+ delete pFirstEntry;
+
+ String aLastName = lcl_GetSpecialNumGroupName( aGroupInfo.End, false, cDecSeparator, aGroupInfo.DateValues, pFormatter );
+ TypedStrData* pLastEntry = new TypedStrData( aLastName, aGroupInfo.End + aGroupInfo.Step, SC_STRTYPE_VALUE );
+ if ( !pCollection->Insert( pLastEntry ) )
+ delete pLastEntry;
+ }
+ }
+ return *pCollection;
+}
+
+// -----------------------------------------------------------------------
+
+String lcl_GetNumGroupForValue( double fValue, const ScDPNumGroupInfo& rInfo, bool bHasNonInteger,
+ sal_Unicode cDecSeparator, double& rGroupValue, ScDocument* pDoc )
+{
+ SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
+
+ if ( fValue < rInfo.Start && !rtl::math::approxEqual( fValue, rInfo.Start ) )
+ {
+ rGroupValue = rInfo.Start - rInfo.Step;
+ return lcl_GetSpecialNumGroupName( rInfo.Start, true, cDecSeparator, rInfo.DateValues, pFormatter );
+ }
+
+ if ( fValue > rInfo.End && !rtl::math::approxEqual( fValue, rInfo.End ) )
+ {
+ rGroupValue = rInfo.End + rInfo.Step;
+ return lcl_GetSpecialNumGroupName( rInfo.End, false, cDecSeparator, rInfo.DateValues, pFormatter );
+ }
+
+ double fDiff = fValue - rInfo.Start;
+ double fDiv = rtl::math::approxFloor( fDiff / rInfo.Step );
+ double fGroupStart = rInfo.Start + fDiv * rInfo.Step;
+
+ if ( rtl::math::approxEqual( fGroupStart, rInfo.End ) &&
+ !rtl::math::approxEqual( fGroupStart, rInfo.Start ) )
+ {
+ if ( !rInfo.DateValues )
+ {
+ // A group that would consist only of the end value is not created,
+ // instead the value is included in the last group before. So the
+ // previous group is used if the calculated group start value is the
+ // selected end value.
+
+ fDiv -= 1.0;
+ fGroupStart = rInfo.Start + fDiv * rInfo.Step;
+ }
+ else
+ {
+ // For date values, the end value is instead treated as above the limit
+ // if it would be a group of its own.
+
+ rGroupValue = rInfo.End + rInfo.Step;
+ return lcl_GetSpecialNumGroupName( rInfo.End, false, cDecSeparator, rInfo.DateValues, pFormatter );
+ }
+ }
+
+ rGroupValue = fGroupStart;
+
+ return lcl_GetNumGroupName( fGroupStart, rInfo, bHasNonInteger, cDecSeparator, pFormatter );
+}
+
+ScDPGroupTableData::ScDPGroupTableData( ScDPTableData* pSource, ScDocument* pDocument ) :
+ ScDPTableData(pDocument),
+ pSourceData( pSource ),
+ pDoc( pDocument )
+{
+ DBG_ASSERT( pSource, "ScDPGroupTableData: pSource can't be NULL" );
+
+ CreateCacheTable();
+ nSourceCount = pSource->GetColumnCount(); // real columns, excluding data layout
+ pNumGroups = new ScDPNumGroupDimension[nSourceCount];
+}
+
+ScDPGroupTableData::~ScDPGroupTableData()
+{
+ delete[] pNumGroups;
+ delete pSourceData;
+}
+
+void ScDPGroupTableData::AddGroupDimension( const ScDPGroupDimension& rGroup )
+{
+ ScDPGroupDimension aNewGroup( rGroup );
+ aNewGroup.SetGroupDim( GetColumnCount() ); // new dimension will be at the end
+ aGroups.push_back( aNewGroup );
+ aGroupNames.insert( OUString(aNewGroup.GetName()) );
+}
+
+void ScDPGroupTableData::SetNumGroupDimension( long nIndex, const ScDPNumGroupDimension& rGroup )
+{
+ if ( nIndex < nSourceCount )
+ {
+ pNumGroups[nIndex] = rGroup;
+
+ // automatic minimum / maximum is handled in GetNumEntries
+ }
+}
+
+long ScDPGroupTableData::GetDimensionIndex( const String& rName )
+{
+ for (long i=0; i<nSourceCount; i++) // nSourceCount excludes data layout
+ if ( pSourceData->getDimensionName(i) == rName ) //! ignore case?
+ return i;
+
+ return -1; // none
+}
+
+long ScDPGroupTableData::GetColumnCount()
+{
+ return nSourceCount + aGroups.size();
+}
+
+bool ScDPGroupTableData::IsNumGroupDimension( long nDimension ) const
+{
+ return ( nDimension < nSourceCount && pNumGroups[nDimension].GetInfo().Enable );
+}
+
+void ScDPGroupTableData::GetNumGroupInfo( long nDimension, ScDPNumGroupInfo& rInfo,
+ bool& rNonInteger, sal_Unicode& rDecimal )
+{
+ if ( nDimension < nSourceCount )
+ {
+ rInfo = pNumGroups[nDimension].GetInfo();
+ rNonInteger = pNumGroups[nDimension].HasNonInteger();
+ rDecimal = pNumGroups[nDimension].GetDecSeparator();
+ }
+}
+
+const TypedScStrCollection& ScDPGroupTableData::GetColumnEntries(long nColumn)
+{
+ // date handling is in ScDPGroupDimension::GetColumnEntries / ScDPNumGroupDimension::GetNumEntries
+ // (to use the pCollection members)
+
+ if ( nColumn >= nSourceCount )
+ {
+ if ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) ) // data layout dimension?
+ nColumn = nSourceCount; // index of data layout in source data
+ else
+ {
+ const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
+ long nSourceDim = rGroupDim.GetSourceDim();
+ // collection is cached at pSourceData, GetColumnEntries can be called every time
+ const TypedScStrCollection& rOriginal = pSourceData->GetColumnEntries( nSourceDim );
+ return rGroupDim.GetColumnEntries( rOriginal, pDoc );
+ }
+ }
+
+ if ( IsNumGroupDimension( nColumn ) )
+ {
+ // dimension number is unchanged for numerical groups
+ const TypedScStrCollection& rOriginal = pSourceData->GetColumnEntries( nColumn );
+ return pNumGroups[nColumn].GetNumEntries( rOriginal, pDoc );
+ }
+
+ return pSourceData->GetColumnEntries( nColumn );
+}
+
+String ScDPGroupTableData::getDimensionName(long nColumn)
+{
+ if ( nColumn >= nSourceCount )
+ {
+ if ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) ) // data layout dimension?
+ nColumn = nSourceCount; // index of data layout in source data
+ else
+ return aGroups[nColumn - nSourceCount].GetName();
+ }
+
+ return pSourceData->getDimensionName( nColumn );
+}
+
+BOOL ScDPGroupTableData::getIsDataLayoutDimension(long nColumn)
+{
+ // position of data layout dimension is moved from source data
+ return ( nColumn == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) ); // data layout dimension?
+}
+
+BOOL ScDPGroupTableData::IsDateDimension(long nDim)
+{
+ if ( nDim >= nSourceCount )
+ {
+ if ( nDim == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) ) // data layout dimension?
+ nDim = nSourceCount; // index of data layout in source data
+ else
+ nDim = aGroups[nDim - nSourceCount].GetSourceDim(); // look at original dimension
+ }
+
+ return pSourceData->IsDateDimension( nDim );
+}
+
+UINT32 ScDPGroupTableData::GetNumberFormat(long nDim)
+{
+ if ( nDim >= nSourceCount )
+ {
+ if ( nDim == sal::static_int_cast<long>( nSourceCount + aGroups.size() ) ) // data layout dimension?
+ nDim = nSourceCount; // index of data layout in source data
+ else
+ nDim = aGroups[nDim - nSourceCount].GetSourceDim(); // look at original dimension
+ }
+
+ return pSourceData->GetNumberFormat( nDim );
+}
+
+void ScDPGroupTableData::DisposeData()
+{
+ for ( ScDPGroupDimensionVec::iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
+ aIter->DisposeData();
+
+ for ( long i=0; i<nSourceCount; i++ )
+ pNumGroups[i].DisposeData();
+
+ pSourceData->DisposeData();
+}
+
+void ScDPGroupTableData::SetEmptyFlags( BOOL bIgnoreEmptyRows, BOOL bRepeatIfEmpty )
+{
+ pSourceData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
+}
+
+bool ScDPGroupTableData::IsRepeatIfEmpty()
+{
+ return pSourceData->IsRepeatIfEmpty();
+}
+
+void ScDPGroupTableData::CreateCacheTable()
+{
+ pSourceData->CreateCacheTable();
+}
+
+void ScDPGroupTableData::ModifyFilterCriteria(vector<ScDPCacheTable::Criterion>& rCriteria)
+{
+ typedef hash_map<long, const ScDPGroupDimension*> GroupFieldMapType;
+ GroupFieldMapType aGroupFieldIds;
+ {
+ ScDPGroupDimensionVec::const_iterator itr = aGroups.begin(), itrEnd = aGroups.end();
+ for (; itr != itrEnd; ++itr)
+ aGroupFieldIds.insert( hash_map<long, const ScDPGroupDimension*>::value_type(itr->GetGroupDim(), &(*itr)) );
+ }
+
+ vector<ScDPCacheTable::Criterion> aNewCriteria;
+ aNewCriteria.reserve(rCriteria.size() + aGroups.size());
+
+ // Go through all the filtered field names and process them appropriately.
+
+ vector<ScDPCacheTable::Criterion>::const_iterator itrEnd = rCriteria.end();
+ GroupFieldMapType::const_iterator itrGrpEnd = aGroupFieldIds.end();
+ for (vector<ScDPCacheTable::Criterion>::const_iterator itr = rCriteria.begin(); itr != itrEnd; ++itr)
+ {
+ ScDPCacheTable::SingleFilter* pFilter = dynamic_cast<ScDPCacheTable::SingleFilter*>(itr->mpFilter.get());
+ if (!pFilter)
+ // We expect this to be a single filter.
+ continue;
+
+ GroupFieldMapType::const_iterator itrGrp = aGroupFieldIds.find(itr->mnFieldIndex);
+ if (itrGrp == itrGrpEnd)
+ {
+ if (IsNumGroupDimension(itr->mnFieldIndex))
+ {
+ // internal number group field
+ const ScDPNumGroupDimension& rNumGrpDim = pNumGroups[itr->mnFieldIndex];
+ const ScDPDateGroupHelper* pDateHelper = rNumGrpDim.GetDateHelper();
+ if (!pDateHelper)
+ {
+ // What do we do here !?
+ continue;
+ }
+
+ ScDPCacheTable::Criterion aCri;
+ aCri.mnFieldIndex = itr->mnFieldIndex;
+ aCri.mpFilter.reset(new ScDPGroupDateFilter(
+ pFilter->getMatchValue(), pDateHelper->GetDatePart(),
+ pDoc->GetFormatTable()->GetNullDate(), &pDateHelper->GetNumInfo()));
+
+ aNewCriteria.push_back(aCri);
+ }
+ else
+ {
+ // This is a regular source field.
+ aNewCriteria.push_back(*itr);
+ }
+ }
+ else
+ {
+ // This is an ordinary group field or external number group field.
+
+ const ScDPGroupDimension* pGrpDim = itrGrp->second;
+ long nSrcDim = pGrpDim->GetSourceDim();
+ const ScDPDateGroupHelper* pDateHelper = pGrpDim->GetDateHelper();
+
+ if (pDateHelper)
+ {
+ // external number group
+ ScDPCacheTable::Criterion aCri;
+ aCri.mnFieldIndex = nSrcDim; // use the source dimension, not the group dimension.
+ aCri.mpFilter.reset(new ScDPGroupDateFilter(
+ pFilter->getMatchValue(), pDateHelper->GetDatePart(),
+ pDoc->GetFormatTable()->GetNullDate(), &pDateHelper->GetNumInfo()));
+
+ aNewCriteria.push_back(aCri);
+ }
+ else
+ {
+ // normal group
+
+ // Note that each group dimension may have multiple group names!
+ size_t nGroupItemCount = pGrpDim->GetItemCount();
+ for (size_t i = 0; i < nGroupItemCount; ++i)
+ {
+ const ScDPGroupItem* pGrpItem = pGrpDim->GetGroupByIndex(i);
+ ScDPItemData aName;
+ aName.aString = pFilter->getMatchString();
+ aName.fValue = pFilter->getMatchValue();
+ aName.bHasValue = pFilter->hasValue();
+ if (!pGrpItem || !pGrpItem->GetName().IsCaseInsEqual(aName))
+ continue;
+
+ ScDPCacheTable::Criterion aCri;
+ aCri.mnFieldIndex = nSrcDim;
+ aCri.mpFilter.reset(new ScDPCacheTable::GroupFilter(GetSharedString()));
+ ScDPCacheTable::GroupFilter* pGrpFilter =
+ static_cast<ScDPCacheTable::GroupFilter*>(aCri.mpFilter.get());
+
+ pGrpItem->FillGroupFilter(*pGrpFilter);
+ aNewCriteria.push_back(aCri);
+ }
+ }
+ }
+ }
+ rCriteria.swap(aNewCriteria);
+}
+
+void ScDPGroupTableData::FilterCacheTable(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims)
+{
+ vector<ScDPCacheTable::Criterion> aNewCriteria(rCriteria);
+ ModifyFilterCriteria(aNewCriteria);
+ pSourceData->FilterCacheTable(aNewCriteria, rCatDims);
+}
+
+void ScDPGroupTableData::GetDrillDownData(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
+{
+ vector<ScDPCacheTable::Criterion> aNewCriteria(rCriteria);
+ ModifyFilterCriteria(aNewCriteria);
+ pSourceData->GetDrillDownData(aNewCriteria, rCatDims, rData);
+}
+
+void ScDPGroupTableData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
+{
+ // This CalcInfo instance is used only to retrive data from the original
+ // data source.
+ CalcInfo aInfoSrc = rInfo;
+ CopyFields(rInfo.aColLevelDims, aInfoSrc.aColLevelDims);
+ CopyFields(rInfo.aRowLevelDims, aInfoSrc.aRowLevelDims);
+ CopyFields(rInfo.aPageDims, aInfoSrc.aPageDims);
+ CopyFields(rInfo.aDataSrcCols, aInfoSrc.aDataSrcCols);
+
+ const ScDPCacheTable& rCacheTable = pSourceData->GetCacheTable();
+ sal_Int32 nRowSize = rCacheTable.getRowSize();
+ for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
+ {
+ if (!rCacheTable.isRowActive(nRow))
+ continue;
+
+ CalcRowData aData;
+ FillRowDataFromCacheTable(nRow, rCacheTable, aInfoSrc, aData);
+
+ if ( !rInfo.aColLevelDims.empty() )
+ FillGroupValues(&aData.aColData[0], rInfo.aColLevelDims.size(), &rInfo.aColLevelDims[0]);
+ if ( !rInfo.aRowLevelDims.empty() )
+ FillGroupValues(&aData.aRowData[0], rInfo.aRowLevelDims.size(), &rInfo.aRowLevelDims[0]);
+ if ( !rInfo.aPageDims.empty() )
+ FillGroupValues(&aData.aPageData[0], rInfo.aPageDims.size(), &rInfo.aPageDims[0]);
+
+ ProcessRowData(rInfo, aData, bAutoShow);
+ }
+}
+
+const ScDPCacheTable& ScDPGroupTableData::GetCacheTable() const
+{
+ return pSourceData->GetCacheTable();
+}
+
+void ScDPGroupTableData::CopyFields(const vector<long>& rFieldDims, vector<long>& rNewFieldDims)
+{
+ size_t nCount = rFieldDims.size();
+ if (!nCount)
+ return;
+
+ long nGroupedColumns = aGroups.size();
+
+ rNewFieldDims.clear();
+ rNewFieldDims.reserve(nCount);
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ if ( rFieldDims[i] >= nSourceCount )
+ {
+ if ( rFieldDims[i] == nSourceCount + nGroupedColumns )
+ // data layout in source
+ rNewFieldDims.push_back(nSourceCount);
+ else
+ {
+ // original dimension
+ long n = rFieldDims[i] - nSourceCount;
+ rNewFieldDims.push_back(aGroups[n].GetSourceDim());
+ }
+ }
+ else
+ rNewFieldDims.push_back(rFieldDims[i]);
+ }
+}
+
+void ScDPGroupTableData::FillGroupValues( ScDPItemData* pItemData, long nCount, const long* pDims )
+{
+ long nGroupedColumns = aGroups.size();
+
+ for (long nDim=0; nDim<nCount; nDim++)
+ {
+ const ScDPDateGroupHelper* pDateHelper = NULL;
+
+ long nColumn = pDims[nDim];
+ if ( nColumn >= nSourceCount && nColumn < nSourceCount + nGroupedColumns )
+ {
+ const ScDPGroupDimension& rGroupDim = aGroups[nColumn - nSourceCount];
+ pDateHelper = rGroupDim.GetDateHelper();
+ if ( !pDateHelper ) // date is handled below
+ {
+ const ScDPGroupItem* pGroupItem = rGroupDim.GetGroupForData( pItemData[nDim] );
+ if ( pGroupItem )
+ pItemData[nDim] = pGroupItem->GetName();
+ // if no group is found, keep the original name
+ }
+ }
+ else if ( IsNumGroupDimension( nColumn ) )
+ {
+ pDateHelper = pNumGroups[nColumn].GetDateHelper();
+ if ( !pDateHelper ) // date is handled below
+ {
+ if ( pItemData[nDim].bHasValue )
+ {
+ ScDPNumGroupInfo aNumInfo;
+ bool bHasNonInteger = false;
+ sal_Unicode cDecSeparator = 0;
+ GetNumGroupInfo( nColumn, aNumInfo, bHasNonInteger, cDecSeparator );
+ double fGroupValue;
+ String aGroupName = lcl_GetNumGroupForValue( pItemData[nDim].fValue,
+ aNumInfo, bHasNonInteger, cDecSeparator, fGroupValue, pDoc );
+
+ // consistent with TypedStrData in GetNumEntries
+ pItemData[nDim] = ScDPItemData( aGroupName, fGroupValue, TRUE );
+ }
+ // else (textual) keep original value
+ }
+ }
+
+ if ( pDateHelper )
+ {
+ if ( pItemData[nDim].bHasValue )
+ {
+ sal_Int32 nPartValue = lcl_GetDatePartValue(
+ pItemData[nDim].fValue, pDateHelper->GetDatePart(), pDoc->GetFormatTable(),
+ &pDateHelper->GetNumInfo() );
+ pItemData[nDim] = ScDPItemData( String(), nPartValue, TRUE );
+ }
+ }
+ }
+}
+
+BOOL ScDPGroupTableData::IsBaseForGroup(long nDim) const
+{
+ for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
+ {
+ const ScDPGroupDimension& rDim = *aIter;
+ if ( rDim.GetSourceDim() == nDim )
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+long ScDPGroupTableData::GetGroupBase(long nGroupDim) const
+{
+ for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
+ {
+ const ScDPGroupDimension& rDim = *aIter;
+ if ( rDim.GetGroupDim() == nGroupDim )
+ return rDim.GetSourceDim();
+ }
+
+ return -1; // none
+}
+
+BOOL ScDPGroupTableData::IsNumOrDateGroup(long nDimension) const
+{
+ // Virtual method from ScDPTableData, used in result data to force text labels.
+
+ if ( nDimension < nSourceCount )
+ {
+ return pNumGroups[nDimension].GetInfo().Enable ||
+ pNumGroups[nDimension].GetDateHelper();
+ }
+
+ for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
+ {
+ const ScDPGroupDimension& rDim = *aIter;
+ if ( rDim.GetGroupDim() == nDimension )
+ return ( rDim.GetDateHelper() != NULL );
+ }
+
+ return FALSE;
+}
+
+BOOL ScDPGroupTableData::IsInGroup( const ScDPItemData& rGroupData, long nGroupIndex,
+ const ScDPItemData& rBaseData, long nBaseIndex ) const
+{
+ for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
+ {
+ const ScDPGroupDimension& rDim = *aIter;
+ if ( rDim.GetGroupDim() == nGroupIndex && rDim.GetSourceDim() == nBaseIndex )
+ {
+ const ScDPDateGroupHelper* pGroupDateHelper = rDim.GetDateHelper();
+ if ( pGroupDateHelper )
+ {
+ //! transform rBaseData (innermost date part)
+ //! -> always do "HasCommonElement" style comparison
+ //! (only Quarter, Month, Day affected)
+
+ const ScDPDateGroupHelper* pBaseDateHelper = NULL;
+ if ( nBaseIndex < nSourceCount )
+ pBaseDateHelper = pNumGroups[nBaseIndex].GetDateHelper();
+
+ // If there's a date group dimension, the base dimension must have
+ // date group information, too.
+ if ( !pBaseDateHelper )
+ {
+ DBG_ERROR( "mix of date and non-date groups" );
+ return TRUE;
+ }
+
+ sal_Int32 nGroupPart = pGroupDateHelper->GetDatePart();
+ sal_Int32 nBasePart = pBaseDateHelper->GetDatePart();
+ return lcl_DateContained( nGroupPart, rGroupData, nBasePart, rBaseData );
+ }
+ else
+ {
+ // If the item is in a group, only that group is valid.
+ // If the item is not in any group, its own name is valid.
+
+ const ScDPGroupItem* pGroup = rDim.GetGroupForData( rBaseData );
+ return pGroup ? pGroup->GetName().IsCaseInsEqual( rGroupData ) :
+ rGroupData.IsCaseInsEqual( rBaseData );
+ }
+ }
+ }
+
+ DBG_ERROR("IsInGroup: no group dimension found");
+ return TRUE;
+}
+
+BOOL ScDPGroupTableData::HasCommonElement( const ScDPItemData& rFirstData, long nFirstIndex,
+ const ScDPItemData& rSecondData, long nSecondIndex ) const
+{
+ const ScDPGroupDimension* pFirstDim = NULL;
+ const ScDPGroupDimension* pSecondDim = NULL;
+ for ( ScDPGroupDimensionVec::const_iterator aIter(aGroups.begin()); aIter != aGroups.end(); aIter++ )
+ {
+ const ScDPGroupDimension* pDim = &(*aIter);
+ if ( pDim->GetGroupDim() == nFirstIndex )
+ pFirstDim = pDim;
+ else if ( pDim->GetGroupDim() == nSecondIndex )
+ pSecondDim = pDim;
+ }
+ if ( pFirstDim && pSecondDim )
+ {
+ const ScDPDateGroupHelper* pFirstDateHelper = pFirstDim->GetDateHelper();
+ const ScDPDateGroupHelper* pSecondDateHelper = pSecondDim->GetDateHelper();
+ if ( pFirstDateHelper || pSecondDateHelper )
+ {
+ // If one is a date group dimension, the other one must be, too.
+ if ( !pFirstDateHelper || !pSecondDateHelper )
+ {
+ DBG_ERROR( "mix of date and non-date groups" );
+ return TRUE;
+ }
+
+ sal_Int32 nFirstPart = pFirstDateHelper->GetDatePart();
+ sal_Int32 nSecondPart = pSecondDateHelper->GetDatePart();
+ return lcl_DateContained( nFirstPart, rFirstData, nSecondPart, rSecondData );
+ }
+
+ const ScDPGroupItem* pFirstItem = pFirstDim->GetGroupForName( rFirstData );
+ const ScDPGroupItem* pSecondItem = pSecondDim->GetGroupForName( rSecondData );
+ if ( pFirstItem && pSecondItem )
+ {
+ // two existing groups -> TRUE if they have a common element
+ return pFirstItem->HasCommonElement( *pSecondItem );
+ }
+ else if ( pFirstItem )
+ {
+ // "automatic" group contains only its own name
+ return pFirstItem->HasElement( rSecondData );
+ }
+ else if ( pSecondItem )
+ {
+ // "automatic" group contains only its own name
+ return pSecondItem->HasElement( rFirstData );
+ }
+ else
+ {
+ // no groups -> TRUE if equal
+ return rFirstData.IsCaseInsEqual( rSecondData );
+ }
+ }
+
+ DBG_ERROR("HasCommonElement: no group dimension found");
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
diff --git a/sc/source/core/data/dpobject.cxx b/sc/source/core/data/dpobject.cxx
new file mode 100644
index 000000000000..22ae204474ec
--- /dev/null
+++ b/sc/source/core/data/dpobject.cxx
@@ -0,0 +1,2536 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dpobject.cxx,v $
+ * $Revision: 1.23.30.5 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "dpobject.hxx"
+#include "dptabsrc.hxx"
+#include "dpsave.hxx"
+#include "dpdimsave.hxx"
+#include "dpoutput.hxx"
+#include "dpshttab.hxx"
+#include "dpsdbtab.hxx"
+#include "dpgroup.hxx"
+#include "document.hxx"
+#include "rechead.hxx"
+#include "pivot.hxx" // PIVOT_DATA_FIELD
+#include "dapiuno.hxx" // ScDataPilotConversion
+#include "miscuno.hxx"
+#include "scerrors.hxx"
+#include "refupdat.hxx"
+#include "scresid.hxx"
+#include "sc.hrc"
+#include "attrib.hxx"
+#include "scitems.hxx"
+#include "unonames.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sheet/GeneralFunction.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
+#include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
+#include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
+#include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
+
+#include <comphelper/processfactory.hxx>
+#include <tools/debug.hxx>
+#include <svtools/zforlist.hxx> // IsNumberFormat
+
+#include <vector>
+
+using namespace com::sun::star;
+using ::std::vector;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::sheet::DataPilotTableHeaderData;
+using ::com::sun::star::sheet::DataPilotTablePositionData;
+using ::com::sun::star::beans::XPropertySet;
+using ::rtl::OUString;
+
+// -----------------------------------------------------------------------
+
+#define MAX_LABELS 256 //!!! from fieldwnd.hxx, must be moved to global.hxx
+
+// -----------------------------------------------------------------------
+
+#define SCDPSOURCE_SERVICE "com.sun.star.sheet.DataPilotSource"
+
+// -----------------------------------------------------------------------
+
+// incompatible versions of data pilot files
+#define SC_DP_VERSION_CURRENT 6
+
+// type of source data
+#define SC_DP_SOURCE_SHEET 0
+#define SC_DP_SOURCE_DATABASE 1
+#define SC_DP_SOURCE_SERVICE 2
+
+// -----------------------------------------------------------------------
+
+//! move to a header file
+#define DP_PROP_COLUMNGRAND "ColumnGrand"
+#define DP_PROP_FUNCTION "Function"
+#define DP_PROP_IGNOREEMPTY "IgnoreEmptyRows"
+#define DP_PROP_ISDATALAYOUT "IsDataLayoutDimension"
+//#define DP_PROP_ISVISIBLE "IsVisible"
+#define DP_PROP_ORIENTATION "Orientation"
+#define DP_PROP_ORIGINAL "Original"
+#define DP_PROP_POSITION "Position"
+#define DP_PROP_REPEATIFEMPTY "RepeatIfEmpty"
+#define DP_PROP_ROWGRAND "RowGrand"
+#define DP_PROP_SHOWDETAILS "ShowDetails"
+#define DP_PROP_SHOWEMPTY "ShowEmpty"
+#define DP_PROP_SUBTOTALS "SubTotals"
+#define DP_PROP_USEDHIERARCHY "UsedHierarchy"
+
+// -----------------------------------------------------------------------
+
+USHORT lcl_GetDataGetOrientation( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
+{
+ long nRet = sheet::DataPilotFieldOrientation_HIDDEN;
+ if ( xSource.is() )
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ long nIntCount = xIntDims->getCount();
+ BOOL bFound = FALSE;
+ for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
+ {
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+ if ( xDimProp.is() )
+ {
+ bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ //! error checking -- is "IsDataLayoutDimension" property required??
+ if (bFound)
+ nRet = ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
+ sheet::DataPilotFieldOrientation_HIDDEN );
+ }
+ }
+ }
+ return static_cast< USHORT >( nRet );
+}
+
+// -----------------------------------------------------------------------
+
+ScDPObject::ScDPObject( ScDocument* pD ) :
+ pDoc( pD ),
+ pSaveData( NULL ),
+ pSheetDesc( NULL ),
+ pImpDesc( NULL ),
+ pServDesc( NULL ),
+ pOutput( NULL ),
+ bSettingsChanged( FALSE ),
+ bAlive( FALSE ),
+ bAllowMove( FALSE ),
+ bInfoValid( FALSE ),
+ nHeaderRows( 0 )
+{
+}
+
+ScDPObject::ScDPObject(const ScDPObject& r) :
+ ScDataObject(),
+ pDoc( r.pDoc ),
+ pSaveData( NULL ),
+ aTableName( r.aTableName ),
+ aTableTag( r.aTableTag ),
+ aOutRange( r.aOutRange ),
+ pSheetDesc( NULL ),
+ pImpDesc( NULL ),
+ pServDesc( NULL ),
+ pOutput( NULL ),
+ bSettingsChanged( FALSE ),
+ bAlive( FALSE ),
+ bAllowMove( FALSE ),
+ bInfoValid( r.bInfoValid ),
+ nHeaderRows( r.nHeaderRows )
+{
+ if (r.pSaveData)
+ pSaveData = new ScDPSaveData(*r.pSaveData);
+ if (r.pSheetDesc)
+ pSheetDesc = new ScSheetSourceDesc(*r.pSheetDesc);
+ if (r.pImpDesc)
+ pImpDesc = new ScImportSourceDesc(*r.pImpDesc);
+ if (r.pServDesc)
+ pServDesc = new ScDPServiceDesc(*r.pServDesc);
+ // xSource (and pOutput) is not copied
+}
+
+ScDPObject::~ScDPObject()
+{
+ delete pOutput;
+ delete pSaveData;
+ delete pSheetDesc;
+ delete pImpDesc;
+ delete pServDesc;
+}
+
+ScDataObject* ScDPObject::Clone() const
+{
+ return new ScDPObject(*this);
+}
+
+void ScDPObject::SetAlive(BOOL bSet)
+{
+ bAlive = bSet;
+}
+
+void ScDPObject::SetAllowMove(BOOL bSet)
+{
+ bAllowMove = bSet;
+}
+
+void ScDPObject::SetSaveData(const ScDPSaveData& rData)
+{
+ if ( pSaveData != &rData ) // API implementation modifies the original SaveData object
+ {
+ delete pSaveData;
+ pSaveData = new ScDPSaveData( rData );
+ }
+
+ InvalidateData(); // re-init source from SaveData
+}
+
+void ScDPObject::SetOutRange(const ScRange& rRange)
+{
+ aOutRange = rRange;
+
+ if ( pOutput )
+ pOutput->SetPosition( rRange.aStart );
+}
+
+void ScDPObject::SetSheetDesc(const ScSheetSourceDesc& rDesc)
+{
+ if ( pSheetDesc && rDesc == *pSheetDesc )
+ return; // nothing to do
+
+ DELETEZ( pImpDesc );
+ DELETEZ( pServDesc );
+
+ delete pImpDesc;
+ pSheetDesc = new ScSheetSourceDesc(rDesc);
+
+ // make valid QueryParam
+
+ pSheetDesc->aQueryParam.nCol1 = pSheetDesc->aSourceRange.aStart.Col();
+ pSheetDesc->aQueryParam.nRow1 = pSheetDesc->aSourceRange.aStart.Row();
+ pSheetDesc->aQueryParam.nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
+ pSheetDesc->aQueryParam.nRow2 = pSheetDesc->aSourceRange.aEnd.Row();;
+ pSheetDesc->aQueryParam.bHasHeader = TRUE;
+
+ InvalidateSource(); // new source must be created
+}
+
+void ScDPObject::SetImportDesc(const ScImportSourceDesc& rDesc)
+{
+ if ( pImpDesc && rDesc == *pImpDesc )
+ return; // nothing to do
+
+ DELETEZ( pSheetDesc );
+ DELETEZ( pServDesc );
+
+ delete pImpDesc;
+ pImpDesc = new ScImportSourceDesc(rDesc);
+
+ InvalidateSource(); // new source must be created
+}
+
+void ScDPObject::SetServiceData(const ScDPServiceDesc& rDesc)
+{
+ if ( pServDesc && rDesc == *pServDesc )
+ return; // nothing to do
+
+ DELETEZ( pSheetDesc );
+ DELETEZ( pImpDesc );
+
+ delete pServDesc;
+ pServDesc = new ScDPServiceDesc(rDesc);
+
+ InvalidateSource(); // new source must be created
+}
+
+void ScDPObject::WriteSourceDataTo( ScDPObject& rDest ) const
+{
+ if ( pSheetDesc )
+ rDest.SetSheetDesc( *pSheetDesc );
+ else if ( pImpDesc )
+ rDest.SetImportDesc( *pImpDesc );
+ else if ( pServDesc )
+ rDest.SetServiceData( *pServDesc );
+
+ // name/tag are not source data, but needed along with source data
+
+ rDest.aTableName = aTableName;
+ rDest.aTableTag = aTableTag;
+}
+
+void ScDPObject::WriteTempDataTo( ScDPObject& rDest ) const
+{
+ rDest.nHeaderRows = nHeaderRows;
+ rDest.bInfoValid = bInfoValid;
+}
+
+BOOL ScDPObject::IsSheetData() const
+{
+ return ( pSheetDesc != NULL );
+}
+
+void ScDPObject::SetName(const String& rNew)
+{
+ aTableName = rNew;
+}
+
+void ScDPObject::SetTag(const String& rNew)
+{
+ aTableTag = rNew;
+}
+
+uno::Reference<sheet::XDimensionsSupplier> ScDPObject::GetSource()
+{
+ CreateObjects();
+ return xSource;
+}
+
+void ScDPObject::CreateOutput()
+{
+ CreateObjects();
+ if (!pOutput)
+ {
+ BOOL bFilterButton = IsSheetData() && pSaveData && pSaveData->GetFilterButton();
+ pOutput = new ScDPOutput( pDoc, xSource, aOutRange.aStart, bFilterButton );
+
+ long nOldRows = nHeaderRows;
+ nHeaderRows = pOutput->GetHeaderRows();
+ bInfoValid = TRUE;
+
+ if ( bAllowMove && nHeaderRows != nOldRows )
+ {
+ long nDiff = nOldRows - nHeaderRows;
+ if ( nOldRows == 0 )
+ --nDiff;
+ if ( nHeaderRows == 0 )
+ ++nDiff;
+
+ long nNewRow = aOutRange.aStart.Row() + nDiff;
+ if ( nNewRow < 0 )
+ nNewRow = 0;
+
+ ScAddress aStart( aOutRange.aStart );
+ aStart.SetRow( (USHORT) nNewRow );
+ pOutput->SetPosition( aStart );
+
+ //! modify aOutRange?
+
+ bAllowMove = FALSE; // use only once
+ }
+ }
+}
+
+void ScDPObject::CreateObjects()
+{
+ // if groups are involved, create a new source with the ScDPGroupTableData
+ if ( bSettingsChanged && pSaveData && pSaveData->GetExistingDimensionData() )
+ xSource = NULL;
+
+ if (!xSource.is())
+ {
+ //! cache DPSource and/or Output?
+
+ DBG_ASSERT( bAlive, "CreateObjects on non-inserted DPObject" );
+
+ DELETEZ( pOutput ); // not valid when xSource is changed
+
+ if ( pServDesc )
+ {
+ xSource = CreateSource( *pServDesc );
+ }
+
+ if ( !xSource.is() ) // database or sheet data, or error in CreateSource
+ {
+ DBG_ASSERT( !pServDesc, "DPSource could not be created" );
+
+ ScDPTableData* pData = NULL;
+ if ( pImpDesc )
+ {
+ // database data
+ pData = new ScDatabaseDPData( pDoc, *pImpDesc );
+ }
+ else
+ {
+ // cell data
+ if (!pSheetDesc)
+ {
+ DBG_ERROR("no source descriptor");
+ pSheetDesc = new ScSheetSourceDesc; // dummy defaults
+ }
+ pData = new ScSheetDPData( pDoc, *pSheetDesc );
+ }
+
+ // grouping (for cell or database data)
+ if ( pSaveData && pSaveData->GetExistingDimensionData() )
+ {
+ ScDPGroupTableData* pGroupData = new ScDPGroupTableData( pData, pDoc );
+ pSaveData->GetExistingDimensionData()->WriteToData( *pGroupData );
+ pData = pGroupData;
+ }
+
+ xSource = new ScDPSource( pData );
+ }
+
+ if (pSaveData)
+ pSaveData->WriteToSource( xSource );
+ }
+ else if (bSettingsChanged)
+ {
+ DELETEZ( pOutput ); // not valid when xSource is changed
+
+ uno::Reference<util::XRefreshable> xRef( xSource, uno::UNO_QUERY );
+ if (xRef.is())
+ {
+ try
+ {
+ xRef->refresh();
+ }
+ catch(uno::Exception&)
+ {
+ DBG_ERROR("exception in refresh");
+ }
+ }
+
+ if (pSaveData)
+ pSaveData->WriteToSource( xSource );
+ }
+ bSettingsChanged = FALSE;
+}
+
+void ScDPObject::InvalidateData()
+{
+ bSettingsChanged = TRUE;
+ bInfoValid = FALSE;
+}
+
+void ScDPObject::InvalidateSource()
+{
+ xSource = NULL;
+ bInfoValid = FALSE;
+}
+
+ScRange ScDPObject::GetNewOutputRange( BOOL& rOverflow )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ rOverflow = pOutput->HasError(); // range overflow or exception from source
+ if ( rOverflow )
+ return ScRange( aOutRange.aStart );
+ else
+ {
+ // don't store the result in aOutRange, because nothing has been output yet
+ return pOutput->GetOutputRange();
+ }
+}
+
+void ScDPObject::Output()
+{
+ // clear old output area
+ pDoc->DeleteAreaTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
+ aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
+ aOutRange.aStart.Tab(), IDF_ALL );
+ pDoc->RemoveFlagsTab( aOutRange.aStart.Col(), aOutRange.aStart.Row(),
+ aOutRange.aEnd.Col(), aOutRange.aEnd.Row(),
+ aOutRange.aStart.Tab(), SC_MF_AUTO );
+
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ pOutput->Output();
+
+ // aOutRange is always the range that was last output to the document
+ aOutRange = pOutput->GetOutputRange();
+}
+
+const ScRange ScDPObject::GetOutputRangeByType( sal_Int32 nType )
+{
+ CreateOutput();
+
+ if (pOutput->HasError())
+ return ScRange(aOutRange.aStart);
+
+ return pOutput->GetOutputRange(nType);
+}
+
+BOOL lcl_HasButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ return ((const ScMergeFlagAttr*)pDoc->GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG ))->HasButton();
+}
+
+void ScDPObject::RefreshAfterLoad()
+{
+ // apply drop-down attribute, initialize nHeaderRows, without accessing the source
+ // (button attribute must be present)
+
+ // simple test: block of button cells at the top, followed by an empty cell
+
+ SCCOL nFirstCol = aOutRange.aStart.Col();
+ SCROW nFirstRow = aOutRange.aStart.Row();
+ SCTAB nTab = aOutRange.aStart.Tab();
+
+ SCROW nInitial = 0;
+ SCROW nOutRows = aOutRange.aEnd.Row() + 1 - aOutRange.aStart.Row();
+ while ( nInitial + 1 < nOutRows && lcl_HasButton( pDoc, nFirstCol, nFirstRow + nInitial, nTab ) )
+ ++nInitial;
+
+ if ( nInitial + 1 < nOutRows &&
+ pDoc->IsBlockEmpty( nTab, nFirstCol, nFirstRow + nInitial, nFirstCol, nFirstRow + nInitial ) &&
+ aOutRange.aEnd.Col() > nFirstCol )
+ {
+ BOOL bFilterButton = IsSheetData(); // when available, filter button setting must be checked here
+
+ SCROW nSkip = bFilterButton ? 1 : 0;
+ for (SCROW nPos=nSkip; nPos<nInitial; nPos++)
+ pDoc->ApplyAttr( nFirstCol + 1, nFirstRow + nPos, nTab, ScMergeFlagAttr(SC_MF_AUTO) );
+
+ nHeaderRows = nInitial;
+ }
+ else
+ nHeaderRows = 0; // nothing found, no drop-down lists
+
+ bInfoValid = TRUE;
+}
+
+void ScDPObject::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ // Output area
+
+ SCCOL nCol1 = aOutRange.aStart.Col();
+ SCROW nRow1 = aOutRange.aStart.Row();
+ SCTAB nTab1 = aOutRange.aStart.Tab();
+ SCCOL nCol2 = aOutRange.aEnd.Col();
+ SCROW nRow2 = aOutRange.aEnd.Row();
+ SCTAB nTab2 = aOutRange.aEnd.Tab();
+
+ ScRefUpdateRes eRes =
+ ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
+ nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if ( eRes != UR_NOTHING )
+ SetOutRange( ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ) );
+
+ // sheet source data
+
+ if ( pSheetDesc )
+ {
+ nCol1 = pSheetDesc->aSourceRange.aStart.Col();
+ nRow1 = pSheetDesc->aSourceRange.aStart.Row();
+ nTab1 = pSheetDesc->aSourceRange.aStart.Tab();
+ nCol2 = pSheetDesc->aSourceRange.aEnd.Col();
+ nRow2 = pSheetDesc->aSourceRange.aEnd.Row();
+ nTab2 = pSheetDesc->aSourceRange.aEnd.Tab();
+
+ eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(), nDx, nDy, nDz,
+ nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if ( eRes != UR_NOTHING )
+ {
+ ScSheetSourceDesc aNewDesc;
+ aNewDesc.aSourceRange = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+
+ SCsCOL nDiffX = nCol1 - (SCsCOL) pSheetDesc->aSourceRange.aStart.Col();
+ SCsROW nDiffY = nRow1 - (SCsROW) pSheetDesc->aSourceRange.aStart.Row();
+
+ aNewDesc.aQueryParam = pSheetDesc->aQueryParam;
+ aNewDesc.aQueryParam.nCol1 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol1 + nDiffX );
+ aNewDesc.aQueryParam.nCol2 = sal::static_int_cast<SCCOL>( aNewDesc.aQueryParam.nCol2 + nDiffX );
+ aNewDesc.aQueryParam.nRow1 += nDiffY; //! used?
+ aNewDesc.aQueryParam.nRow2 += nDiffY; //! used?
+ SCSIZE nEC = aNewDesc.aQueryParam.GetEntryCount();
+ for (SCSIZE i=0; i<nEC; i++)
+ if (aNewDesc.aQueryParam.GetEntry(i).bDoQuery)
+ aNewDesc.aQueryParam.GetEntry(i).nField += nDiffX;
+
+ SetSheetDesc( aNewDesc ); // allocates new pSheetDesc
+ }
+ }
+}
+
+BOOL ScDPObject::RefsEqual( const ScDPObject& r ) const
+{
+ if ( aOutRange != r.aOutRange )
+ return FALSE;
+
+ if ( pSheetDesc && r.pSheetDesc )
+ {
+ if ( pSheetDesc->aSourceRange != r.pSheetDesc->aSourceRange )
+ return FALSE;
+ }
+ else if ( pSheetDesc || r.pSheetDesc )
+ {
+ DBG_ERROR("RefsEqual: SheetDesc set at only one object");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void ScDPObject::WriteRefsTo( ScDPObject& r ) const
+{
+ r.SetOutRange( aOutRange );
+ if ( pSheetDesc )
+ r.SetSheetDesc( *pSheetDesc );
+}
+
+void ScDPObject::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
+{
+ CreateOutput();
+ pOutput->GetPositionData(rPos, rPosData);
+}
+
+bool ScDPObject::GetDataFieldPositionData(
+ const ScAddress& rPos, Sequence<sheet::DataPilotFieldFilter>& rFilters)
+{
+ CreateOutput();
+
+ vector<sheet::DataPilotFieldFilter> aFilters;
+ if (!pOutput->GetDataResultPositionData(aFilters, rPos))
+ return false;
+
+ sal_Int32 n = static_cast<sal_Int32>(aFilters.size());
+ rFilters.realloc(n);
+ for (sal_Int32 i = 0; i < n; ++i)
+ rFilters[i] = aFilters[i];
+
+ return true;
+}
+
+void ScDPObject::GetDrillDownData(const ScAddress& rPos, Sequence< Sequence<Any> >& rTableData)
+{
+ CreateOutput();
+
+ Reference<sheet::XDrillDownDataSupplier> xDrillDownData(xSource, UNO_QUERY);
+ if (!xDrillDownData.is())
+ return;
+
+ Sequence<sheet::DataPilotFieldFilter> filters;
+ if (!GetDataFieldPositionData(rPos, filters))
+ return;
+
+ rTableData = xDrillDownData->getDrillDownData(filters);
+}
+
+BOOL ScDPObject::IsDimNameInUse( const String& rName ) const
+{
+ if ( xSource.is() )
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ if ( xDimsName.is() )
+ {
+ rtl::OUString aCompare( rName );
+ uno::Sequence<rtl::OUString> aNames = xDimsName->getElementNames();
+ long nCount = aNames.getLength();
+ const rtl::OUString* pArr = aNames.getConstArray();
+ for (long nPos=0; nPos<nCount; nPos++)
+ if ( pArr[nPos] == aCompare ) //! ignore case
+ return TRUE;
+ }
+ }
+ return FALSE; // not found
+}
+
+String ScDPObject::GetDimName( long nDim, BOOL& rIsDataLayout )
+{
+ rIsDataLayout = FALSE;
+ String aRet;
+
+ if ( xSource.is() )
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ long nDimCount = xDims->getCount();
+ if ( nDim < nDimCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+ if ( xDimName.is() && xDimProp.is() )
+ {
+ BOOL bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ //! error checking -- is "IsDataLayoutDimension" property required??
+
+ rtl::OUString aName;
+ try
+ {
+ aName = xDimName->getName();
+ }
+ catch(uno::Exception&)
+ {
+ }
+ if ( bData )
+ rIsDataLayout = TRUE;
+ else
+ aRet = String( aName );
+ }
+ }
+ }
+
+ return aRet;
+}
+
+BOOL ScDPObject::IsDuplicated( long nDim )
+{
+ BOOL bDuplicated = FALSE;
+ if ( xSource.is() )
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ long nDimCount = xDims->getCount();
+ if ( nDim < nDimCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+ if ( xDimProp.is() )
+ {
+ try
+ {
+ uno::Any aOrigAny = xDimProp->getPropertyValue(
+ rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
+ uno::Reference<uno::XInterface> xIntOrig;
+ if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
+ bDuplicated = TRUE;
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ return bDuplicated;
+}
+
+long ScDPObject::GetDimCount()
+{
+ long nRet = 0;
+ if ( xSource.is() )
+ {
+ try
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ if ( xDimsName.is() )
+ nRet = xDimsName->getElementNames().getLength();
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ return nRet;
+}
+
+void ScDPObject::FillPageList( TypedScStrCollection& rStrings, long nField )
+{
+ //! merge members access with ToggleDetails?
+
+ //! convert field index to dimension index?
+
+ DBG_ASSERT( xSource.is(), "no source" );
+ if ( !xSource.is() ) return;
+
+ uno::Reference<container::XNamed> xDim;
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ long nIntCount = xIntDims->getCount();
+ if ( nField < nIntCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
+ xIntDims->getByIndex(nField) );
+ xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
+ }
+ DBG_ASSERT( xDim.is(), "dimension not found" );
+ if ( !xDim.is() ) return;
+
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
+ long nLevel = 0;
+
+ long nHierCount = 0;
+ uno::Reference<container::XIndexAccess> xHiers;
+ uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
+ xHiers = new ScNameToIndexAccess( xHiersName );
+ nHierCount = xHiers->getCount();
+ }
+ uno::Reference<uno::XInterface> xHier;
+ if ( nHierarchy < nHierCount )
+ xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHierarchy) );
+ DBG_ASSERT( xHier.is(), "hierarchy not found" );
+ if ( !xHier.is() ) return;
+
+ long nLevCount = 0;
+ uno::Reference<container::XIndexAccess> xLevels;
+ uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
+ if ( xLevSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
+ xLevels = new ScNameToIndexAccess( xLevsName );
+ nLevCount = xLevels->getCount();
+ }
+ uno::Reference<uno::XInterface> xLevel;
+ if ( nLevel < nLevCount )
+ xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(nLevel) );
+ DBG_ASSERT( xLevel.is(), "level not found" );
+ if ( !xLevel.is() ) return;
+
+ uno::Reference<container::XNameAccess> xMembers;
+ uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
+ if ( xMbrSupp.is() )
+ xMembers = xMbrSupp->getMembers();
+ DBG_ASSERT( xMembers.is(), "members not found" );
+ if ( !xMembers.is() ) return;
+
+ uno::Sequence<rtl::OUString> aNames = xMembers->getElementNames();
+ long nNameCount = aNames.getLength();
+ const rtl::OUString* pNameArr = aNames.getConstArray();
+ for (long nPos = 0; nPos < nNameCount; ++nPos)
+ {
+ // Make sure to insert only visible members.
+ Reference<XPropertySet> xPropSet(xMembers->getByName(pNameArr[nPos]), UNO_QUERY);
+ sal_Bool bVisible = false;
+ if (xPropSet.is())
+ {
+ Any any = xPropSet->getPropertyValue(OUString::createFromAscii(SC_UNO_ISVISIBL));
+ any >>= bVisible;
+ }
+
+ if (bVisible)
+ {
+ // use the order from getElementNames
+ TypedStrData* pData = new TypedStrData( pNameArr[nPos] );
+ if ( !rStrings.AtInsert( rStrings.GetCount(), pData ) )
+ delete pData;
+ }
+ }
+
+ // add "-all-" entry to the top (unsorted)
+ TypedStrData* pAllData = new TypedStrData( String( ScResId( SCSTR_ALL ) ) ); //! separate string? (also output)
+ if ( !rStrings.AtInsert( 0, pAllData ) )
+ delete pAllData;
+}
+
+void ScDPObject::GetHeaderPositionData(const ScAddress& rPos, DataPilotTableHeaderData& rData)
+{
+ using namespace ::com::sun::star::sheet::DataPilotTablePositionType;
+
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ // Reset member values to invalid state.
+ rData.Dimension = rData.Hierarchy = rData.Level = -1;
+ rData.Flags = 0;
+
+ DataPilotTablePositionData aPosData;
+ pOutput->GetPositionData(rPos, aPosData);
+ const sal_Int32 nPosType = aPosData.PositionType;
+ if (nPosType == COLUMN_HEADER || nPosType == ROW_HEADER)
+ aPosData.PositionData >>= rData;
+}
+
+// Returns TRUE on success and stores the result in rTarget
+BOOL ScDPObject::GetPivotData( ScDPGetPivotDataField& rTarget,
+ const std::vector< ScDPGetPivotDataField >& rFilters )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ return pOutput->GetPivotData( rTarget, rFilters );
+}
+
+BOOL ScDPObject::IsFilterButton( const ScAddress& rPos )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ return pOutput->IsFilterButton( rPos );
+}
+
+long ScDPObject::GetHeaderDim( const ScAddress& rPos, USHORT& rOrient )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ return pOutput->GetHeaderDim( rPos, rOrient );
+}
+
+BOOL ScDPObject::GetHeaderDrag( const ScAddress& rPos, BOOL bMouseLeft, BOOL bMouseTop, long nDragDim,
+ Rectangle& rPosRect, USHORT& rOrient, long& rDimPos )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ return pOutput->GetHeaderDrag( rPos, bMouseLeft, bMouseTop, nDragDim, rPosRect, rOrient, rDimPos );
+}
+
+void ScDPObject::GetMemberResultNames( ScStrCollection& rNames, long nDimension )
+{
+ CreateOutput(); // create xSource and pOutput if not already done
+
+ pOutput->GetMemberResultNames( rNames, nDimension ); // used only with table data -> level not needed
+}
+
+bool lcl_Dequote( const String& rSource, xub_StrLen nStartPos, xub_StrLen& rEndPos, String& rResult )
+{
+ // nStartPos has to point to opening quote
+
+ bool bRet = false;
+ const sal_Unicode cQuote = '\'';
+
+ if ( rSource.GetChar(nStartPos) == cQuote )
+ {
+ rtl::OUStringBuffer aBuffer;
+ xub_StrLen nPos = nStartPos + 1;
+ const xub_StrLen nLen = rSource.Len();
+
+ while ( nPos < nLen )
+ {
+ const sal_Unicode cNext = rSource.GetChar(nPos);
+ if ( cNext == cQuote )
+ {
+ if ( nPos+1 < nLen && rSource.GetChar(nPos+1) == cQuote )
+ {
+ // double quote is used for an embedded quote
+ aBuffer.append( cNext ); // append one quote
+ ++nPos; // skip the next one
+ }
+ else
+ {
+ // end of quoted string
+ rResult = aBuffer.makeStringAndClear();
+ rEndPos = nPos + 1; // behind closing quote
+ return true;
+ }
+ }
+ else
+ aBuffer.append( cNext );
+
+ ++nPos;
+ }
+ // no closing quote before the end of the string -> error (bRet still false)
+ }
+
+ return bRet;
+}
+
+struct ScGetPivotDataFunctionEntry
+{
+ const sal_Char* pName;
+ sheet::GeneralFunction eFunc;
+};
+
+bool lcl_ParseFunction( const String& rList, xub_StrLen nStartPos, xub_StrLen& rEndPos, sheet::GeneralFunction& rFunc )
+{
+ static const ScGetPivotDataFunctionEntry aFunctions[] =
+ {
+ // our names
+ { "Sum", sheet::GeneralFunction_SUM },
+ { "Count", sheet::GeneralFunction_COUNT },
+ { "Average", sheet::GeneralFunction_AVERAGE },
+ { "Max", sheet::GeneralFunction_MAX },
+ { "Min", sheet::GeneralFunction_MIN },
+ { "Product", sheet::GeneralFunction_PRODUCT },
+ { "CountNums", sheet::GeneralFunction_COUNTNUMS },
+ { "StDev", sheet::GeneralFunction_STDEV },
+ { "StDevp", sheet::GeneralFunction_STDEVP },
+ { "Var", sheet::GeneralFunction_VAR },
+ { "VarP", sheet::GeneralFunction_VARP },
+ // compatibility names
+ { "Count Nums", sheet::GeneralFunction_COUNTNUMS },
+ { "StdDev", sheet::GeneralFunction_STDEV },
+ { "StdDevp", sheet::GeneralFunction_STDEVP }
+ };
+
+ const xub_StrLen nListLen = rList.Len();
+ while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
+ ++nStartPos;
+
+ bool bParsed = false;
+ bool bFound = false;
+ String aFuncStr;
+ xub_StrLen nFuncEnd = 0;
+ if ( nStartPos < nListLen && rList.GetChar(nStartPos) == '\'' )
+ bParsed = lcl_Dequote( rList, nStartPos, nFuncEnd, aFuncStr );
+ else
+ {
+ nFuncEnd = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
+ if ( nFuncEnd != STRING_NOTFOUND )
+ {
+ aFuncStr = rList.Copy( nStartPos, nFuncEnd - nStartPos );
+ bParsed = true;
+ }
+ }
+
+ if ( bParsed )
+ {
+ aFuncStr.EraseLeadingAndTrailingChars( ' ' );
+
+ const sal_Int32 nFuncCount = sizeof(aFunctions) / sizeof(aFunctions[0]);
+ for ( sal_Int32 nFunc=0; nFunc<nFuncCount && !bFound; nFunc++ )
+ {
+ if ( aFuncStr.EqualsIgnoreCaseAscii( aFunctions[nFunc].pName ) )
+ {
+ rFunc = aFunctions[nFunc].eFunc;
+ bFound = true;
+
+ while ( nFuncEnd < nListLen && rList.GetChar(nFuncEnd) == ' ' )
+ ++nFuncEnd;
+ rEndPos = nFuncEnd;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+bool lcl_IsAtStart( const String& rList, const String& rSearch, sal_Int32& rMatched,
+ bool bAllowBracket, sheet::GeneralFunction* pFunc )
+{
+ sal_Int32 nMatchList = 0;
+ sal_Int32 nMatchSearch = 0;
+ sal_Unicode cFirst = rList.GetChar(0);
+ if ( cFirst == '\'' || cFirst == '[' )
+ {
+ // quoted string or string in brackets must match completely
+
+ String aDequoted;
+ xub_StrLen nQuoteEnd = 0;
+ bool bParsed = false;
+
+ if ( cFirst == '\'' )
+ bParsed = lcl_Dequote( rList, 0, nQuoteEnd, aDequoted );
+ else if ( cFirst == '[' )
+ {
+ // skip spaces after the opening bracket
+
+ xub_StrLen nStartPos = 1;
+ const xub_StrLen nListLen = rList.Len();
+ while ( nStartPos < nListLen && rList.GetChar(nStartPos) == ' ' )
+ ++nStartPos;
+
+ if ( rList.GetChar(nStartPos) == '\'' ) // quoted within the brackets?
+ {
+ if ( lcl_Dequote( rList, nStartPos, nQuoteEnd, aDequoted ) )
+ {
+ // after the quoted string, there must be the closing bracket, optionally preceded by spaces,
+ // and/or a function name
+ while ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ' ' )
+ ++nQuoteEnd;
+
+ // semicolon separates function name
+ if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ';' && pFunc )
+ {
+ xub_StrLen nFuncEnd = 0;
+ if ( lcl_ParseFunction( rList, nQuoteEnd + 1, nFuncEnd, *pFunc ) )
+ nQuoteEnd = nFuncEnd;
+ }
+ if ( nQuoteEnd < nListLen && rList.GetChar(nQuoteEnd) == ']' )
+ {
+ ++nQuoteEnd; // include the closing bracket for the matched length
+ bParsed = true;
+ }
+ }
+ }
+ else
+ {
+ // implicit quoting to the closing bracket
+
+ xub_StrLen nClosePos = rList.Search( static_cast<sal_Unicode>(']'), nStartPos );
+ if ( nClosePos != STRING_NOTFOUND )
+ {
+ xub_StrLen nNameEnd = nClosePos;
+ xub_StrLen nSemiPos = rList.Search( static_cast<sal_Unicode>(';'), nStartPos );
+ if ( nSemiPos != STRING_NOTFOUND && nSemiPos < nClosePos && pFunc )
+ {
+ xub_StrLen nFuncEnd = 0;
+ if ( lcl_ParseFunction( rList, nSemiPos + 1, nFuncEnd, *pFunc ) )
+ nNameEnd = nSemiPos;
+ }
+
+ aDequoted = rList.Copy( nStartPos, nNameEnd - nStartPos );
+ aDequoted.EraseTrailingChars( ' ' ); // spaces before the closing bracket or semicolon
+ nQuoteEnd = nClosePos + 1;
+ bParsed = true;
+ }
+ }
+ }
+
+ if ( bParsed && ScGlobal::pTransliteration->isEqual( aDequoted, rSearch ) )
+ {
+ nMatchList = nQuoteEnd; // match count in the list string, including quotes
+ nMatchSearch = rSearch.Len();
+ }
+ }
+ else
+ {
+ // otherwise look for search string at the start of rList
+ ScGlobal::pTransliteration->equals( rList, 0, rList.Len(), nMatchList,
+ rSearch, 0, rSearch.Len(), nMatchSearch );
+ }
+
+ if ( nMatchSearch == rSearch.Len() )
+ {
+ // search string is at start of rList - look for following space or end of string
+
+ bool bValid = false;
+ if ( sal::static_int_cast<xub_StrLen>(nMatchList) >= rList.Len() )
+ bValid = true;
+ else
+ {
+ sal_Unicode cNext = rList.GetChar(sal::static_int_cast<xub_StrLen>(nMatchList));
+ if ( cNext == ' ' || ( bAllowBracket && cNext == '[' ) )
+ bValid = true;
+ }
+
+ if ( bValid )
+ {
+ rMatched = nMatchList;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+BOOL ScDPObject::ParseFilters( ScDPGetPivotDataField& rTarget,
+ std::vector< ScDPGetPivotDataField >& rFilters,
+ const String& rFilterList )
+{
+ // parse the string rFilterList into parameters for GetPivotData
+
+ CreateObjects(); // create xSource if not already done
+
+ std::vector<String> aDataNames; // data fields (source name)
+ std::vector<String> aGivenNames; // data fields (compound name)
+ std::vector<String> aFieldNames; // column/row/data fields
+ std::vector< uno::Sequence<rtl::OUString> > aFieldValues;
+
+ //
+ // get all the field and item names
+ //
+
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ sal_Int32 nDimCount = xIntDims->getCount();
+ for ( sal_Int32 nDim = 0; nDim<nDimCount; nDim++ )
+ {
+ uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nDim) );
+ uno::Reference<container::XNamed> xDim( xIntDim, uno::UNO_QUERY );
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
+ BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ sal_Int32 nOrient = ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
+ sheet::DataPilotFieldOrientation_HIDDEN );
+ if ( !bDataLayout )
+ {
+ if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
+ {
+ String aSourceName;
+ String aGivenName;
+ ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xIntDim );
+ aDataNames.push_back( aSourceName );
+ aGivenNames.push_back( aGivenName );
+ }
+ else if ( nOrient != sheet::DataPilotFieldOrientation_HIDDEN )
+ {
+ // get level names, as in ScDPOutput
+
+ uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
+ sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
+ if ( nHierarchy >= xHiers->getCount() )
+ nHierarchy = 0;
+
+ uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
+ xHiers->getByIndex(nHierarchy) );
+ uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
+ sal_Int32 nLevCount = xLevels->getCount();
+ for (sal_Int32 nLev=0; nLev<nLevCount; nLev++)
+ {
+ uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface(
+ xLevels->getByIndex(nLev) );
+ uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
+ uno::Reference<sheet::XMembersSupplier> xLevSupp( xLevel, uno::UNO_QUERY );
+ if ( xLevNam.is() && xLevSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xMembers = xLevSupp->getMembers();
+
+ String aFieldName( xLevNam->getName() );
+ uno::Sequence<rtl::OUString> aMemberNames( xMembers->getElementNames() );
+
+ aFieldNames.push_back( aFieldName );
+ aFieldValues.push_back( aMemberNames );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // compare and build filters
+ //
+
+ SCSIZE nDataFields = aDataNames.size();
+ SCSIZE nFieldCount = aFieldNames.size();
+ DBG_ASSERT( aGivenNames.size() == nDataFields && aFieldValues.size() == nFieldCount, "wrong count" );
+
+ bool bError = false;
+ bool bHasData = false;
+ String aRemaining( rFilterList );
+ aRemaining.EraseLeadingAndTrailingChars( ' ' );
+ while ( aRemaining.Len() && !bError )
+ {
+ bool bUsed = false;
+
+ // look for data field name
+
+ for ( SCSIZE nDataPos=0; nDataPos<nDataFields && !bUsed; nDataPos++ )
+ {
+ String aFound;
+ sal_Int32 nMatched = 0;
+ if ( lcl_IsAtStart( aRemaining, aDataNames[nDataPos], nMatched, false, NULL ) )
+ aFound = aDataNames[nDataPos];
+ else if ( lcl_IsAtStart( aRemaining, aGivenNames[nDataPos], nMatched, false, NULL ) )
+ aFound = aGivenNames[nDataPos];
+
+ if ( aFound.Len() )
+ {
+ rTarget.maFieldName = aFound;
+ aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
+ bHasData = true;
+ bUsed = true;
+ }
+ }
+
+ // look for field name
+
+ String aSpecField;
+ bool bHasFieldName = false;
+ if ( !bUsed )
+ {
+ sal_Int32 nMatched = 0;
+ for ( SCSIZE nField=0; nField<nFieldCount && !bHasFieldName; nField++ )
+ {
+ if ( lcl_IsAtStart( aRemaining, aFieldNames[nField], nMatched, true, NULL ) )
+ {
+ aSpecField = aFieldNames[nField];
+ aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
+ aRemaining.EraseLeadingChars( ' ' );
+
+ // field name has to be followed by item name in brackets
+ if ( aRemaining.GetChar(0) == '[' )
+ {
+ bHasFieldName = true;
+ // bUsed remains false - still need the item
+ }
+ else
+ {
+ bUsed = true;
+ bError = true;
+ }
+ }
+ }
+ }
+
+ // look for field item
+
+ if ( !bUsed )
+ {
+ bool bItemFound = false;
+ sal_Int32 nMatched = 0;
+ String aFoundName;
+ String aFoundValue;
+ sheet::GeneralFunction eFunc = sheet::GeneralFunction_NONE;
+ sheet::GeneralFunction eFoundFunc = sheet::GeneralFunction_NONE;
+
+ for ( SCSIZE nField=0; nField<nFieldCount; nField++ )
+ {
+ // If a field name is given, look in that field only, otherwise in all fields.
+ // aSpecField is initialized from aFieldNames array, so exact comparison can be used.
+ if ( !bHasFieldName || aFieldNames[nField] == aSpecField )
+ {
+ const uno::Sequence<rtl::OUString>& rItems = aFieldValues[nField];
+ sal_Int32 nItemCount = rItems.getLength();
+ const rtl::OUString* pItemArr = rItems.getConstArray();
+ for ( sal_Int32 nItem=0; nItem<nItemCount; nItem++ )
+ {
+ if ( lcl_IsAtStart( aRemaining, pItemArr[nItem], nMatched, false, &eFunc ) )
+ {
+ if ( bItemFound )
+ bError = true; // duplicate (also across fields)
+ else
+ {
+ aFoundName = aFieldNames[nField];
+ aFoundValue = pItemArr[nItem];
+ eFoundFunc = eFunc;
+ bItemFound = true;
+ bUsed = true;
+ }
+ }
+ }
+ }
+ }
+
+ if ( bItemFound && !bError )
+ {
+ ScDPGetPivotDataField aField;
+ aField.maFieldName = aFoundName;
+ aField.meFunction = eFoundFunc;
+ aField.mbValIsStr = true;
+ aField.maValStr = aFoundValue;
+ aField.mnValNum = 0.0;
+ rFilters.push_back( aField );
+
+ aRemaining.Erase( 0, sal::static_int_cast<xub_StrLen>(nMatched) );
+ }
+ }
+
+ if ( !bUsed )
+ bError = true;
+
+ aRemaining.EraseLeadingChars( ' ' ); // remove any number of spaces between entries
+ }
+
+ if ( !bError && !bHasData && aDataNames.size() == 1 )
+ {
+ // if there's only one data field, its name need not be specified
+ rTarget.maFieldName = aDataNames[0];
+ bHasData = true;
+ }
+
+ return bHasData && !bError;
+}
+
+void ScDPObject::ToggleDetails(const DataPilotTableHeaderData& rElemDesc, ScDPObject* pDestObj)
+{
+ CreateObjects(); // create xSource if not already done
+
+ // find dimension name
+
+ uno::Reference<container::XNamed> xDim;
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ long nIntCount = xIntDims->getCount();
+ if ( rElemDesc.Dimension < nIntCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
+ xIntDims->getByIndex(rElemDesc.Dimension) );
+ xDim = uno::Reference<container::XNamed>( xIntDim, uno::UNO_QUERY );
+ }
+ DBG_ASSERT( xDim.is(), "dimension not found" );
+ if ( !xDim.is() ) return;
+ String aDimName = xDim->getName();
+
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ if (bDataLayout)
+ {
+ // the elements of the data layout dimension can't be found by their names
+ // -> don't change anything
+ return;
+ }
+
+ // query old state
+
+ long nHierCount = 0;
+ uno::Reference<container::XIndexAccess> xHiers;
+ uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
+ xHiers = new ScNameToIndexAccess( xHiersName );
+ nHierCount = xHiers->getCount();
+ }
+ uno::Reference<uno::XInterface> xHier;
+ if ( rElemDesc.Hierarchy < nHierCount )
+ xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(rElemDesc.Hierarchy) );
+ DBG_ASSERT( xHier.is(), "hierarchy not found" );
+ if ( !xHier.is() ) return;
+
+ long nLevCount = 0;
+ uno::Reference<container::XIndexAccess> xLevels;
+ uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
+ if ( xLevSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
+ xLevels = new ScNameToIndexAccess( xLevsName );
+ nLevCount = xLevels->getCount();
+ }
+ uno::Reference<uno::XInterface> xLevel;
+ if ( rElemDesc.Level < nLevCount )
+ xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(rElemDesc.Level) );
+ DBG_ASSERT( xLevel.is(), "level not found" );
+ if ( !xLevel.is() ) return;
+
+ uno::Reference<container::XNameAccess> xMembers;
+ uno::Reference<sheet::XMembersSupplier> xMbrSupp( xLevel, uno::UNO_QUERY );
+ if ( xMbrSupp.is() )
+ xMembers = xMbrSupp->getMembers();
+
+ BOOL bFound = FALSE;
+ BOOL bShowDetails = TRUE;
+
+ if ( xMembers.is() )
+ {
+ if ( xMembers->hasByName(rElemDesc.MemberName) )
+ {
+ uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
+ xMembers->getByName(rElemDesc.MemberName) );
+ uno::Reference<beans::XPropertySet> xMbrProp( xMemberInt, uno::UNO_QUERY );
+ if ( xMbrProp.is() )
+ {
+ bShowDetails = ScUnoHelpFunctions::GetBoolProperty( xMbrProp,
+ rtl::OUString::createFromAscii(DP_PROP_SHOWDETAILS) );
+ //! don't set bFound if property is unknown?
+ bFound = TRUE;
+ }
+ }
+ }
+
+ DBG_ASSERT( bFound, "member not found" );
+
+ //! use Hierarchy and Level in SaveData !!!!
+
+ // modify pDestObj if set, this object otherwise
+ ScDPSaveData* pModifyData = pDestObj ? ( pDestObj->pSaveData ) : pSaveData;
+ DBG_ASSERT( pModifyData, "no data?" );
+ if ( pModifyData )
+ {
+ const String aName = rElemDesc.MemberName;
+ pModifyData->GetDimensionByName(aDimName)->
+ GetMemberByName(aName)->SetShowDetails( !bShowDetails ); // toggle
+
+ if ( pDestObj )
+ pDestObj->InvalidateData(); // re-init source from SaveData
+ else
+ InvalidateData(); // re-init source from SaveData
+ }
+}
+
+long lcl_FindName( const rtl::OUString& rString, const uno::Reference<container::XNameAccess>& xCollection )
+{
+ if ( xCollection.is() )
+ {
+ uno::Sequence<rtl::OUString> aSeq = xCollection->getElementNames();
+ long nCount = aSeq.getLength();
+ const rtl::OUString* pArr = aSeq.getConstArray();
+ for (long nPos=0; nPos<nCount; nPos++)
+ if ( pArr[nPos] == rString )
+ return nPos;
+ }
+ return -1; // not found
+}
+
+USHORT lcl_FirstSubTotal( const uno::Reference<beans::XPropertySet>& xDimProp ) // PIVOT_FUNC mask
+{
+ uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
+ if ( xDimProp.is() && xDimSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
+ long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
+ if ( nHierarchy >= xHiers->getCount() )
+ nHierarchy = 0;
+
+ uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
+ xHiers->getByIndex(nHierarchy) );
+ uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
+ uno::Reference<uno::XInterface> xLevel =
+ ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
+ uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
+ if ( xLevProp.is() )
+ {
+ uno::Any aSubAny;
+ try
+ {
+ aSubAny = xLevProp->getPropertyValue(
+ rtl::OUString::createFromAscii(DP_PROP_SUBTOTALS) );
+ }
+ catch(uno::Exception&)
+ {
+ }
+ uno::Sequence<sheet::GeneralFunction> aSeq;
+ if ( aSubAny >>= aSeq )
+ {
+ USHORT nMask = 0;
+ const sheet::GeneralFunction* pArray = aSeq.getConstArray();
+ long nCount = aSeq.getLength();
+ for (long i=0; i<nCount; i++)
+ nMask |= ScDataPilotConversion::FunctionBit(pArray[i]);
+ return nMask;
+ }
+ }
+ }
+ }
+
+ DBG_ERROR("FirstSubTotal: NULL");
+ return 0;
+}
+
+USHORT lcl_CountBits( USHORT nBits )
+{
+ if (!nBits) return 0;
+
+ USHORT nCount = 0;
+ USHORT nMask = 1;
+ for (USHORT i=0; i<16; i++)
+ {
+ if ( nBits & nMask )
+ ++nCount;
+ nMask <<= 1;
+ }
+ return nCount;
+}
+
+SCSIZE lcl_FillOldFields( PivotField* pFields,
+ const uno::Reference<sheet::XDimensionsSupplier>& xSource,
+ USHORT nOrient, SCCOL nColAdd, BOOL bAddData )
+{
+ SCSIZE nOutCount = 0;
+ BOOL bDataFound = FALSE;
+
+ SCSIZE nCount = (nOrient == sheet::DataPilotFieldOrientation_PAGE) ? PIVOT_MAXPAGEFIELD : PIVOT_MAXFIELD;
+
+ //! merge multiple occurences (data field with different functions)
+ //! force data field in one dimension
+
+ std::vector< long > aPos( nCount, 0 );
+
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ long nDimCount = xDims->getCount();
+ for (long nDim=0; nDim < nDimCount && nOutCount < nCount; nDim++)
+ {
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+ long nDimOrient = ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
+ sheet::DataPilotFieldOrientation_HIDDEN );
+ if ( xDimProp.is() && nDimOrient == nOrient )
+ {
+ USHORT nMask = 0;
+ if ( nOrient == sheet::DataPilotFieldOrientation_DATA )
+ {
+ sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_FUNCTION),
+ sheet::GeneralFunction_NONE );
+ if ( eFunc == sheet::GeneralFunction_AUTO )
+ {
+ //! test for numeric data
+ eFunc = sheet::GeneralFunction_SUM;
+ }
+ nMask = ScDataPilotConversion::FunctionBit(eFunc);
+ }
+ else
+ nMask = lcl_FirstSubTotal( xDimProp ); // from first hierarchy
+
+ BOOL bDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ uno::Any aOrigAny;
+ try
+ {
+ aOrigAny = xDimProp->getPropertyValue(
+ rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
+ }
+ catch(uno::Exception&)
+ {
+ }
+
+ long nDupSource = -1;
+ uno::Reference<uno::XInterface> xIntOrig = ScUnoHelpFunctions::AnyToInterface( aOrigAny );
+ if ( xIntOrig.is() )
+ {
+ uno::Reference<container::XNamed> xNameOrig( xIntOrig, uno::UNO_QUERY );
+ if ( xNameOrig.is() )
+ nDupSource = lcl_FindName( xNameOrig->getName(), xDimsName );
+ }
+
+ BOOL bDupUsed = FALSE;
+ if ( nDupSource >= 0 )
+ {
+ // add function bit to previous entry
+
+ SCsCOL nCompCol;
+ if ( bDataLayout )
+ nCompCol = PIVOT_DATA_FIELD;
+ else
+ nCompCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek source column from name
+
+ for (SCSIZE nOld=0; nOld<nOutCount && !bDupUsed; nOld++)
+ if ( pFields[nOld].nCol == nCompCol )
+ {
+ // add to previous column only if new bits aren't already set there
+ if ( ( pFields[nOld].nFuncMask & nMask ) == 0 )
+ {
+ pFields[nOld].nFuncMask |= nMask;
+ pFields[nOld].nFuncCount = lcl_CountBits( pFields[nOld].nFuncMask );
+ bDupUsed = TRUE;
+ }
+ }
+ }
+
+ if ( !bDupUsed ) // also for duplicated dim if original has different orientation
+ {
+ if ( bDataLayout )
+ {
+ pFields[nOutCount].nCol = PIVOT_DATA_FIELD;
+ bDataFound = TRUE;
+ }
+ else if ( nDupSource >= 0 ) // if source was not found (different orientation)
+ pFields[nOutCount].nCol = static_cast<SCsCOL>(nDupSource)+nColAdd; //! seek from name
+ else
+ pFields[nOutCount].nCol = static_cast<SCsCOL>(nDim)+nColAdd; //! seek source column from name
+
+ pFields[nOutCount].nFuncMask = nMask;
+ pFields[nOutCount].nFuncCount = lcl_CountBits( nMask );
+ aPos[nOutCount] = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_POSITION) );
+
+ try
+ {
+ if( nOrient == sheet::DataPilotFieldOrientation_DATA )
+ xDimProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_REFVALUE ) ) )
+ >>= pFields[nOutCount].maFieldRef;
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ ++nOutCount;
+ }
+ }
+ }
+
+ // sort by getPosition() value
+
+ for (SCSIZE i=0; i+1<nOutCount; i++)
+ {
+ for (SCSIZE j=0; j+i+1<nOutCount; j++)
+ if ( aPos[j+1] < aPos[j] )
+ {
+ std::swap( aPos[j], aPos[j+1] );
+ std::swap( pFields[j], pFields[j+1] );
+ }
+ }
+
+ if ( bAddData && !bDataFound )
+ {
+ if ( nOutCount >= nCount ) // space for data field?
+ --nOutCount; //! error?
+ pFields[nOutCount].nCol = PIVOT_DATA_FIELD;
+ pFields[nOutCount].nFuncMask = 0;
+ pFields[nOutCount].nFuncCount = 0;
+ ++nOutCount;
+ }
+
+ return nOutCount;
+}
+
+BOOL ScDPObject::FillOldParam(ScPivotParam& rParam, BOOL bForFile) const
+{
+ ((ScDPObject*)this)->CreateObjects(); // xSource is needed for field numbers
+
+ rParam.nCol = aOutRange.aStart.Col();
+ rParam.nRow = aOutRange.aStart.Row();
+ rParam.nTab = aOutRange.aStart.Tab();
+ // ppLabelArr / nLabels is not changed
+
+ SCCOL nColAdd = 0;
+ if ( bForFile )
+ {
+ // in old file format, columns are within document, not within source range
+
+ DBG_ASSERT( pSheetDesc, "FillOldParam: bForFile, !pSheetDesc" );
+ nColAdd = pSheetDesc->aSourceRange.aStart.Col();
+ }
+
+ BOOL bAddData = ( lcl_GetDataGetOrientation( xSource ) == sheet::DataPilotFieldOrientation_HIDDEN );
+ rParam.nPageCount = lcl_FillOldFields( rParam.aPageArr,
+ xSource, sheet::DataPilotFieldOrientation_PAGE, nColAdd, FALSE );
+ rParam.nColCount = lcl_FillOldFields( rParam.aColArr,
+ xSource, sheet::DataPilotFieldOrientation_COLUMN, nColAdd, bAddData );
+ rParam.nRowCount = lcl_FillOldFields( rParam.aRowArr,
+ xSource, sheet::DataPilotFieldOrientation_ROW, nColAdd, FALSE );
+ rParam.nDataCount = lcl_FillOldFields( rParam.aDataArr,
+ xSource, sheet::DataPilotFieldOrientation_DATA, nColAdd, FALSE );
+
+ uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
+ if (xProp.is())
+ {
+ try
+ {
+ rParam.bMakeTotalCol = ScUnoHelpFunctions::GetBoolProperty( xProp,
+ rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND), TRUE );
+ rParam.bMakeTotalRow = ScUnoHelpFunctions::GetBoolProperty( xProp,
+ rtl::OUString::createFromAscii(DP_PROP_ROWGRAND), TRUE );
+
+ // following properties may be missing for external sources
+ rParam.bIgnoreEmptyRows = ScUnoHelpFunctions::GetBoolProperty( xProp,
+ rtl::OUString::createFromAscii(DP_PROP_IGNOREEMPTY) );
+ rParam.bDetectCategories = ScUnoHelpFunctions::GetBoolProperty( xProp,
+ rtl::OUString::createFromAscii(DP_PROP_REPEATIFEMPTY) );
+ }
+ catch(uno::Exception&)
+ {
+ // no error
+ }
+ }
+ return TRUE;
+}
+
+void lcl_FillLabelData( LabelData& rData, const uno::Reference< beans::XPropertySet >& xDimProp )
+{
+ uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDimProp, uno::UNO_QUERY );
+ if ( xDimProp.is() && xDimSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xHiers = new ScNameToIndexAccess( xDimSupp->getHierarchies() );
+ long nHierarchy = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
+ if ( nHierarchy >= xHiers->getCount() )
+ nHierarchy = 0;
+ rData.mnUsedHier = nHierarchy;
+
+ uno::Reference<uno::XInterface> xHier = ScUnoHelpFunctions::AnyToInterface(
+ xHiers->getByIndex(nHierarchy) );
+
+ uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess( xHierSupp->getLevels() );
+ uno::Reference<uno::XInterface> xLevel =
+ ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( 0 ) );
+ uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
+ if ( xLevProp.is() )
+ {
+ rData.mbShowAll = ScUnoHelpFunctions::GetBoolProperty( xLevProp,
+ rtl::OUString::createFromAscii(DP_PROP_SHOWEMPTY) );
+
+ try
+ {
+ xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SORTING ) ) )
+ >>= rData.maSortInfo;
+ xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_LAYOUT ) ) )
+ >>= rData.maLayoutInfo;
+ xLevProp->getPropertyValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_AUTOSHOW ) ) )
+ >>= rData.maShowInfo;
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+}
+
+BOOL ScDPObject::FillLabelData(ScPivotParam& rParam)
+{
+ ((ScDPObject*)this)->CreateObjects();
+
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ long nDimCount = xDims->getCount();
+ if ( nDimCount > MAX_LABELS )
+ nDimCount = MAX_LABELS;
+ if (!nDimCount)
+ return FALSE;
+
+ SCSIZE nOutCount = 0;
+ LabelData** aLabelArr = new LabelData*[nDimCount];
+ for (long nDim=0; nDim < nDimCount; nDim++)
+ {
+ String aFieldName;
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+
+ if ( xDimName.is() && xDimProp.is() )
+ {
+ BOOL bDuplicated = FALSE;
+ BOOL bData = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ //! error checking -- is "IsDataLayoutDimension" property required??
+
+ try
+ {
+ aFieldName = String( xDimName->getName() );
+
+ uno::Any aOrigAny = xDimProp->getPropertyValue(
+ rtl::OUString::createFromAscii(DP_PROP_ORIGINAL) );
+ uno::Reference<uno::XInterface> xIntOrig;
+ if ( (aOrigAny >>= xIntOrig) && xIntOrig.is() )
+ bDuplicated = TRUE;
+ }
+ catch(uno::Exception&)
+ {
+ }
+
+ if ( aFieldName.Len() && !bData && !bDuplicated )
+ {
+ SCsCOL nCol = static_cast< SCsCOL >( nDim ); //! ???
+ bool bIsValue = true; //! check
+
+ aLabelArr[nOutCount] = new LabelData( aFieldName, nCol, bIsValue );
+
+ LabelData& rLabelData = *aLabelArr[nOutCount];
+ GetHierarchies( nDim, rLabelData.maHiers );
+ GetMembers( nDim, rLabelData.maMembers, &rLabelData.maVisible, &rLabelData.maShowDet );
+ lcl_FillLabelData( rLabelData, xDimProp );
+
+ ++nOutCount;
+ }
+ }
+ }
+
+ rParam.SetLabelData( aLabelArr, nOutCount );
+
+ for (SCSIZE i=0; i<nOutCount; i++)
+ delete aLabelArr[i];
+ delete[] aLabelArr;
+
+ return TRUE;
+}
+
+BOOL ScDPObject::GetHierarchiesNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xHiers )
+{
+ BOOL bRet = FALSE;
+ uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
+ uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
+ if( xIntDims.is() )
+ {
+ uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
+ if (xHierSup.is())
+ {
+ xHiers.set( xHierSup->getHierarchies() );
+ bRet = xHiers.is();
+ }
+ }
+ return bRet;
+}
+
+BOOL ScDPObject::GetHierarchies( sal_Int32 nDim, uno::Sequence< rtl::OUString >& rHiers )
+{
+ BOOL bRet = FALSE;
+ uno::Reference< container::XNameAccess > xHiersNA;
+ if( GetHierarchiesNA( nDim, xHiersNA ) )
+ {
+ rHiers = xHiersNA->getElementNames();
+ bRet = TRUE;
+ }
+ return bRet;
+}
+
+sal_Int32 ScDPObject::GetUsedHierarchy( sal_Int32 nDim )
+{
+ sal_Int32 nHier = 0;
+ uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
+ uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
+ uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
+ if (xDim.is())
+ nHier = ScUnoHelpFunctions::GetLongProperty( xDim, rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( SC_UNO_USEDHIER ) ) );
+ return nHier;
+}
+
+BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, uno::Reference< container::XNameAccess >& xMembers )
+{
+ return GetMembersNA( nDim, GetUsedHierarchy( nDim ), xMembers );
+}
+
+BOOL ScDPObject::GetMembers( sal_Int32 nDim,
+ uno::Sequence< rtl::OUString >& rMembers,
+ uno::Sequence< sal_Bool >* pVisible,
+ uno::Sequence< sal_Bool >* pShowDet )
+{
+ return GetMembers( nDim, GetUsedHierarchy( nDim ), rMembers, pVisible, pShowDet );
+}
+
+BOOL ScDPObject::GetMembersNA( sal_Int32 nDim, sal_Int32 nHier, uno::Reference< container::XNameAccess >& xMembers )
+{
+ BOOL bRet = FALSE;
+ uno::Reference<container::XNameAccess> xDimsName( GetSource()->getDimensions() );
+ uno::Reference<container::XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
+ uno::Reference<beans::XPropertySet> xDim(xIntDims->getByIndex( nDim ), uno::UNO_QUERY);
+ if (xDim.is())
+ {
+ uno::Reference<sheet::XHierarchiesSupplier> xHierSup(xDim, uno::UNO_QUERY);
+ if (xHierSup.is())
+ {
+ uno::Reference<container::XIndexAccess> xHiers(new ScNameToIndexAccess(xHierSup->getHierarchies()));
+ uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHiers->getByIndex(nHier), uno::UNO_QUERY );
+ if ( xLevSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xLevels(new ScNameToIndexAccess( xLevSupp->getLevels()));
+ if (xLevels.is())
+ {
+ sal_Int32 nLevCount = xLevels->getCount();
+ if (nLevCount > 0)
+ {
+ uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevels->getByIndex(0), uno::UNO_QUERY );
+ if ( xMembSupp.is() )
+ {
+ xMembers.set(xMembSupp->getMembers());
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+BOOL ScDPObject::GetMembers( sal_Int32 nDim, sal_Int32 nHier,
+ uno::Sequence< rtl::OUString >& rMembers,
+ uno::Sequence< sal_Bool >* pVisible,
+ uno::Sequence< sal_Bool >* pShowDet )
+{
+ BOOL bRet = FALSE;
+ uno::Reference< container::XNameAccess > xMembersNA;
+ if( GetMembersNA( nDim, nHier, xMembersNA ) )
+ {
+ uno::Reference< container::XIndexAccess > xMembersIA( new ScNameToIndexAccess( xMembersNA ) );
+ sal_Int32 nCount = xMembersIA->getCount();
+ rMembers.realloc( nCount );
+ if( pVisible )
+ pVisible->realloc( nCount );
+ if( pShowDet )
+ pShowDet->realloc( nCount );
+
+ rtl::OUString* pAry = rMembers.getArray();
+ for( sal_Int32 nItem = 0; nItem < nCount; ++nItem )
+ {
+ uno::Reference< container::XNamed > xMember( xMembersIA->getByIndex( nItem ), uno::UNO_QUERY );
+ if( xMember.is() )
+ pAry[ nItem ] = xMember->getName();
+ if( pVisible || pShowDet )
+ {
+ uno::Reference< beans::XPropertySet > xMemProp( xMember, uno::UNO_QUERY );
+ if( pVisible )
+ {
+ sal_Bool bVis = sal_True;
+ if( xMemProp.is() )
+ bVis = ScUnoHelpFunctions::GetBoolProperty( xMemProp,
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_ISVISIBL ) ) );
+ (*pVisible)[ nItem ] = bVis;
+ }
+ if( pShowDet )
+ {
+ sal_Bool bShow = sal_True;
+ if( xMemProp.is() )
+ bShow = ScUnoHelpFunctions::GetBoolProperty( xMemProp,
+ rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( SC_UNO_SHOWDETA ) ) );
+ (*pShowDet)[ nItem ] = bShow;
+ }
+ }
+ }
+ bRet = TRUE;
+ }
+ return bRet;
+}
+
+//------------------------------------------------------------------------
+// convert old pivot tables into new datapilot tables
+
+String lcl_GetDimName( const uno::Reference<sheet::XDimensionsSupplier>& xSource, long nDim )
+{
+ rtl::OUString aName;
+ if ( xSource.is() )
+ {
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xDimsName );
+ long nDimCount = xDims->getCount();
+ if ( nDim < nDimCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
+ if (xDimName.is())
+ {
+ try
+ {
+ aName = xDimName->getName();
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ return aName;
+}
+
+// static
+void ScDPObject::ConvertOrientation( ScDPSaveData& rSaveData,
+ PivotField* pFields, SCSIZE nCount, USHORT nOrient,
+ ScDocument* pDoc, SCROW nRow, SCTAB nTab,
+ const uno::Reference<sheet::XDimensionsSupplier>& xSource,
+ BOOL bOldDefaults,
+ PivotField* pRefColFields, SCSIZE nRefColCount,
+ PivotField* pRefRowFields, SCSIZE nRefRowCount,
+ PivotField* pRefPageFields, SCSIZE nRefPageCount )
+{
+ // pDoc or xSource must be set
+ DBG_ASSERT( pDoc || xSource.is(), "missing string source" );
+
+ String aDocStr;
+ ScDPSaveDimension* pDim;
+
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ SCCOL nCol = pFields[i].nCol;
+ USHORT nFuncs = pFields[i].nFuncMask;
+ const sheet::DataPilotFieldReference& rFieldRef = pFields[i].maFieldRef;
+
+ if ( nCol == PIVOT_DATA_FIELD )
+ pDim = rSaveData.GetDataLayoutDimension();
+ else
+ {
+ if ( pDoc )
+ pDoc->GetString( nCol, nRow, nTab, aDocStr );
+ else
+ aDocStr = lcl_GetDimName( xSource, nCol ); // cols must start at 0
+
+ if ( aDocStr.Len() )
+ pDim = rSaveData.GetDimensionByName(aDocStr);
+ else
+ pDim = NULL;
+ }
+
+ if ( pDim )
+ {
+ if ( nOrient == sheet::DataPilotFieldOrientation_DATA ) // set summary function
+ {
+ // generate an individual entry for each function
+ BOOL bFirst = TRUE;
+
+ // if a dimension is used for column/row/page and data,
+ // use duplicated dimensions for all data occurrences
+ if (pRefColFields)
+ for (SCSIZE nRefCol=0; nRefCol<nRefColCount; nRefCol++)
+ if (pRefColFields[nRefCol].nCol == nCol)
+ bFirst = FALSE;
+ if (pRefRowFields)
+ for (SCSIZE nRefRow=0; nRefRow<nRefRowCount; nRefRow++)
+ if (pRefRowFields[nRefRow].nCol == nCol)
+ bFirst = FALSE;
+ if (pRefPageFields)
+ for (USHORT nRefPage=0; nRefPage<nRefPageCount; ++nRefPage)
+ if (pRefPageFields[nRefPage].nCol == nCol)
+ bFirst = FALSE;
+
+ // if set via api, a data column may occur several times
+ // (if the function hasn't been changed yet) -> also look for duplicate data column
+ for (SCSIZE nPrevData=0; nPrevData<i; nPrevData++)
+ if (pFields[nPrevData].nCol == nCol)
+ bFirst = FALSE;
+
+ USHORT nMask = 1;
+ for (USHORT nBit=0; nBit<16; nBit++)
+ {
+ if ( nFuncs & nMask )
+ {
+ sheet::GeneralFunction eFunc = ScDataPilotConversion::FirstFunc( nMask );
+ ScDPSaveDimension* pCurrDim = bFirst ? pDim : rSaveData.DuplicateDimension(pDim->GetName());
+ pCurrDim->SetOrientation( nOrient );
+ pCurrDim->SetFunction( sal::static_int_cast<USHORT>(eFunc) );
+
+ if( rFieldRef.ReferenceType == sheet::DataPilotFieldReferenceType::NONE )
+ pCurrDim->SetReferenceValue( 0 );
+ else
+ pCurrDim->SetReferenceValue( &rFieldRef );
+
+ bFirst = FALSE;
+ }
+ nMask *= 2;
+ }
+ }
+ else // set SubTotals
+ {
+ pDim->SetOrientation( nOrient );
+
+ USHORT nFuncArray[16];
+ USHORT nFuncCount = 0;
+ USHORT nMask = 1;
+ for (USHORT nBit=0; nBit<16; nBit++)
+ {
+ if ( nFuncs & nMask )
+ nFuncArray[nFuncCount++] = sal::static_int_cast<USHORT>(ScDataPilotConversion::FirstFunc( nMask ));
+ nMask *= 2;
+ }
+ pDim->SetSubTotals( nFuncCount, nFuncArray );
+
+ // ShowEmpty was implicit in old tables,
+ // must be set for data layout dimension (not accessible in dialog)
+ if ( bOldDefaults || nCol == PIVOT_DATA_FIELD )
+ pDim->SetShowEmpty( TRUE );
+ }
+ }
+ }
+}
+
+#if OLD_PIVOT_IMPLEMENTATION
+void ScDPObject::InitFromOldPivot( const ScPivot& rOld, ScDocument* pDocP, BOOL bSetSource )
+{
+ ScDPSaveData aSaveData;
+
+ ScPivotParam aParam;
+ ScQueryParam aQuery;
+ ScArea aArea;
+ rOld.GetParam( aParam, aQuery, aArea );
+
+ ConvertOrientation( aSaveData, aParam.aPageArr, aParam.nPageCount,
+ sheet::DataPilotFieldOrientation_PAGE, pDocP, aArea.nRowStart, aArea.nTab,
+ uno::Reference<sheet::XDimensionsSupplier>(), TRUE );
+ ConvertOrientation( aSaveData, aParam.aColArr, aParam.nColCount,
+ sheet::DataPilotFieldOrientation_COLUMN, pDocP, aArea.nRowStart, aArea.nTab,
+ uno::Reference<sheet::XDimensionsSupplier>(), TRUE );
+ ConvertOrientation( aSaveData, aParam.aRowArr, aParam.nRowCount,
+ sheet::DataPilotFieldOrientation_ROW, pDocP, aArea.nRowStart, aArea.nTab,
+ uno::Reference<sheet::XDimensionsSupplier>(), TRUE );
+ ConvertOrientation( aSaveData, aParam.aDataArr, aParam.nDataCount,
+ sheet::DataPilotFieldOrientation_DATA, pDocP, aArea.nRowStart, aArea.nTab,
+ uno::Reference<sheet::XDimensionsSupplier>(), TRUE,
+ aParam.aColArr, aParam.nColCount, aParam.aRowArr, aParam.nRowCount );
+
+ aSaveData.SetIgnoreEmptyRows( rOld.GetIgnoreEmpty() );
+ aSaveData.SetRepeatIfEmpty( rOld.GetDetectCat() );
+ aSaveData.SetColumnGrand( rOld.GetMakeTotalCol() );
+ aSaveData.SetRowGrand( rOld.GetMakeTotalRow() );
+
+ SetSaveData( aSaveData );
+ if (bSetSource)
+ {
+ ScSheetSourceDesc aDesc;
+ aDesc.aSourceRange = rOld.GetSrcArea();
+ rOld.GetQuery( aDesc.aQueryParam );
+ SetSheetDesc( aDesc );
+ }
+ SetOutRange( rOld.GetDestArea() );
+
+ aTableName = rOld.GetName();
+ aTableTag = rOld.GetTag();
+}
+#endif
+
+// -----------------------------------------------------------------------
+
+// static
+BOOL ScDPObject::HasRegisteredSources()
+{
+ BOOL bFound = FALSE;
+
+ uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
+ uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
+ if ( xEnAc.is() )
+ {
+ uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
+ rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
+ if ( xEnum.is() && xEnum->hasMoreElements() )
+ bFound = TRUE;
+ }
+
+ return bFound;
+}
+
+// static
+uno::Sequence<rtl::OUString> ScDPObject::GetRegisteredSources()
+{
+ long nCount = 0;
+ uno::Sequence<rtl::OUString> aSeq(0);
+
+ // use implementation names...
+
+ uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
+ uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
+ if ( xEnAc.is() )
+ {
+ uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
+ rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
+ if ( xEnum.is() )
+ {
+ while ( xEnum->hasMoreElements() )
+ {
+ uno::Any aAddInAny = xEnum->nextElement();
+// if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
+ {
+ uno::Reference<uno::XInterface> xIntFac;
+ aAddInAny >>= xIntFac;
+ if ( xIntFac.is() )
+ {
+ uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
+ if ( xInfo.is() )
+ {
+ rtl::OUString sName = xInfo->getImplementationName();
+
+ aSeq.realloc( nCount+1 );
+ aSeq.getArray()[nCount] = sName;
+ ++nCount;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return aSeq;
+}
+
+// static
+uno::Reference<sheet::XDimensionsSupplier> ScDPObject::CreateSource( const ScDPServiceDesc& rDesc )
+{
+ rtl::OUString aImplName = rDesc.aServiceName;
+ uno::Reference<sheet::XDimensionsSupplier> xRet = NULL;
+
+ uno::Reference<lang::XMultiServiceFactory> xManager = comphelper::getProcessServiceFactory();
+ uno::Reference<container::XContentEnumerationAccess> xEnAc( xManager, uno::UNO_QUERY );
+ if ( xEnAc.is() )
+ {
+ uno::Reference<container::XEnumeration> xEnum = xEnAc->createContentEnumeration(
+ rtl::OUString::createFromAscii( SCDPSOURCE_SERVICE ) );
+ if ( xEnum.is() )
+ {
+ while ( xEnum->hasMoreElements() && !xRet.is() )
+ {
+ uno::Any aAddInAny = xEnum->nextElement();
+// if ( aAddInAny.getReflection()->getTypeClass() == TypeClass_INTERFACE )
+ {
+ uno::Reference<uno::XInterface> xIntFac;
+ aAddInAny >>= xIntFac;
+ if ( xIntFac.is() )
+ {
+ uno::Reference<lang::XServiceInfo> xInfo( xIntFac, uno::UNO_QUERY );
+ uno::Reference<lang::XSingleServiceFactory> xFac( xIntFac, uno::UNO_QUERY );
+ if ( xFac.is() && xInfo.is() && xInfo->getImplementationName() == aImplName )
+ {
+ try
+ {
+ uno::Reference<uno::XInterface> xInterface = xFac->createInstance();
+ uno::Reference<lang::XInitialization> xInit( xInterface, uno::UNO_QUERY );
+ if (xInit.is())
+ {
+ // initialize
+ uno::Sequence<uno::Any> aSeq(4);
+ uno::Any* pArray = aSeq.getArray();
+ pArray[0] <<= rtl::OUString( rDesc.aParSource );
+ pArray[1] <<= rtl::OUString( rDesc.aParName );
+ pArray[2] <<= rtl::OUString( rDesc.aParUser );
+ pArray[3] <<= rtl::OUString( rDesc.aParPass );
+ xInit->initialize( aSeq );
+ }
+ xRet = uno::Reference<sheet::XDimensionsSupplier>( xInterface, uno::UNO_QUERY );
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return xRet;
+}
+
+// ============================================================================
+
+ScDPCacheCell::ScDPCacheCell() :
+ mnStrId(ScSimpleSharedString::EMPTY),
+ mnType(SC_VALTYPE_EMPTY),
+ mfValue(0.0),
+ mbNumeric(false)
+{
+}
+
+ScDPCacheCell::ScDPCacheCell(const ScDPCacheCell& r) :
+ mnStrId(r.mnStrId),
+ mnType(r.mnType),
+ mfValue(r.mfValue),
+ mbNumeric(r.mbNumeric)
+{
+}
+
+ScDPCacheCell::~ScDPCacheCell()
+{
+}
+
+// ============================================================================
+
+size_t ScDPCollection::CacheCellHash::operator()(const ScDPCacheCell* pCell) const
+{
+ return pCell->mnStrId + static_cast<size_t>(pCell->mnType) +
+ static_cast<size_t>(pCell->mfValue) + static_cast<size_t>(pCell->mbNumeric);
+}
+
+bool ScDPCollection::CacheCellEqual::operator()(const ScDPCacheCell* p1, const ScDPCacheCell* p2) const
+{
+ if (!p1 && !p2)
+ return true;
+
+ if ((!p1 && p2) || (p1 && !p2))
+ return false;
+
+ return p1->mnStrId == p2->mnStrId && p1->mfValue == p2->mfValue &&
+ p1->mbNumeric == p2->mbNumeric && p1->mnType == p2->mnType;
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPCollection::ScDPCollection(ScDocument* pDocument) :
+ pDoc( pDocument )
+{
+}
+
+ScDPCollection::ScDPCollection(const ScDPCollection& r) :
+ ScCollection(r),
+ pDoc(r.pDoc),
+ maSharedString(r.maSharedString),
+ maCacheCellPool(r.maCacheCellPool)
+{
+}
+
+ScDPCollection::~ScDPCollection()
+{
+ clearCacheCellPool();
+}
+
+ScDataObject* ScDPCollection::Clone() const
+{
+ return new ScDPCollection(*this);
+}
+
+void ScDPCollection::DeleteOnTab( SCTAB nTab )
+{
+ USHORT nPos = 0;
+ while ( nPos < nCount )
+ {
+ // look for output positions on the deleted sheet
+ if ( static_cast<const ScDPObject*>(At(nPos))->GetOutRange().aStart.Tab() == nTab )
+ AtFree(nPos);
+ else
+ ++nPos;
+ }
+}
+
+void ScDPCollection::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& r, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ for (USHORT i=0; i<nCount; i++)
+ ((ScDPObject*)At(i))->UpdateReference( eUpdateRefMode, r, nDx, nDy, nDz );
+}
+
+BOOL ScDPCollection::RefsEqual( const ScDPCollection& r ) const
+{
+ if ( nCount != r.nCount )
+ return FALSE;
+
+ for (USHORT i=0; i<nCount; i++)
+ if ( ! ((const ScDPObject*)At(i))->RefsEqual( *((const ScDPObject*)r.At(i)) ) )
+ return FALSE;
+
+ return TRUE; // all equal
+}
+
+void ScDPCollection::WriteRefsTo( ScDPCollection& r ) const
+{
+ if ( nCount == r.nCount )
+ {
+ //! assert equal names?
+ for (USHORT i=0; i<nCount; i++)
+ ((const ScDPObject*)At(i))->WriteRefsTo( *((ScDPObject*)r.At(i)) );
+ }
+ else
+ {
+ // #i8180# If data pilot tables were deleted with their sheet,
+ // this collection contains extra entries that must be restored.
+ // Matching objects are found by their names.
+
+ DBG_ASSERT( nCount >= r.nCount, "WriteRefsTo: missing entries in document" );
+ for (USHORT nSourcePos=0; nSourcePos<nCount; nSourcePos++)
+ {
+ const ScDPObject* pSourceObj = static_cast<const ScDPObject*>(At(nSourcePos));
+ String aName = pSourceObj->GetName();
+ bool bFound = false;
+ for (USHORT nDestPos=0; nDestPos<r.nCount && !bFound; nDestPos++)
+ {
+ ScDPObject* pDestObj = static_cast<ScDPObject*>(r.At(nDestPos));
+ if ( pDestObj->GetName() == aName )
+ {
+ pSourceObj->WriteRefsTo( *pDestObj ); // found object, copy refs
+ bFound = true;
+ }
+ }
+ if ( !bFound )
+ {
+ // none found, re-insert deleted object (see ScUndoDataPilot::Undo)
+
+ ScDPObject* pDestObj = new ScDPObject( *pSourceObj );
+ pDestObj->SetAlive(TRUE);
+ if ( !r.Insert(pDestObj) )
+ {
+ DBG_ERROR("cannot insert DPObject");
+ DELETEZ( pDestObj );
+ }
+ }
+ }
+ DBG_ASSERT( nCount == r.nCount, "WriteRefsTo: couldn't restore all entries" );
+ }
+}
+
+String ScDPCollection::CreateNewName( USHORT nMin ) const
+{
+ String aBase = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("DataPilot"));
+ //! from Resource?
+
+ for (USHORT nAdd=0; nAdd<=nCount; nAdd++) // nCount+1 tries
+ {
+ String aNewName = aBase;
+ aNewName += String::CreateFromInt32( nMin + nAdd );
+ BOOL bFound = FALSE;
+ for (USHORT i=0; i<nCount && !bFound; i++)
+ if (((const ScDPObject*)pItems[i])->GetName() == aNewName)
+ bFound = TRUE;
+ if (!bFound)
+ return aNewName; // found unused Name
+ }
+ return String(); // should not happen
+}
+
+ScSimpleSharedString& ScDPCollection::GetSharedString()
+{
+ return maSharedString;
+}
+
+ScDPCacheCell* ScDPCollection::getCacheCellFromPool(const ScDPCacheCell& rCell)
+{
+ ScDPCacheCell aCell(rCell);
+ CacheCellPoolType::iterator itr = maCacheCellPool.find(&aCell);
+ if (itr == maCacheCellPool.end())
+ {
+ // Insert a new instance.
+ ScDPCacheCell* p = new ScDPCacheCell(rCell);
+ ::std::pair<CacheCellPoolType::iterator, bool> r =
+ maCacheCellPool.insert(p);
+ if (!r.second)
+ delete p;
+
+ ScDPCacheCell* p2 = r.second ? *r.first : NULL;
+ DBG_ASSERT(p == p2, "ScDPCollection::getCacheCellFromPool: pointer addresses differ");
+ return p2;
+ }
+ return *itr;
+}
+
+namespace {
+
+class DeleteCacheCells : public ::std::unary_function<ScDPCacheCell*, void>
+{
+public:
+ void operator()(ScDPCacheCell* p) const
+ {
+ delete p;
+ }
+};
+
+}
+
+void ScDPCollection::clearCacheCellPool()
+{
+ // Transferring all stored pointers to a vector first. For some unknown
+ // reason, deleting cell content instances by directly iterating through
+ // the hash set causes the iteration to return an identical pointer
+ // value twice, causing a double-delete. I have no idea why this happens.
+
+ using ::std::copy;
+ using ::std::back_inserter;
+
+ vector<ScDPCacheCell*> ps;
+ ps.reserve(maCacheCellPool.size());
+ copy(maCacheCellPool.begin(), maCacheCellPool.end(), back_inserter(ps));
+ for_each(ps.begin(), ps.end(), DeleteCacheCells());
+ maCacheCellPool.clear();
+}
+
+//------------------------------------------------------------------------
+// convert old pivot tables into new datapilot tables
+
+#if OLD_PIVOT_IMPLEMENTATION
+void ScDPCollection::ConvertOldTables( ScPivotCollection& rOldColl )
+{
+ // convert old pivot tables into new datapilot tables
+
+ USHORT nOldCount = rOldColl.GetCount();
+ for (USHORT i=0; i<nOldCount; i++)
+ {
+ ScDPObject* pNewObj = new ScDPObject(pDoc);
+ pNewObj->InitFromOldPivot( *(rOldColl)[i], pDoc, TRUE );
+ pNewObj->SetAlive( TRUE );
+ Insert( pNewObj );
+ }
+ rOldColl.FreeAll();
+}
+#endif
+
+
+
+
diff --git a/sc/source/core/data/dpoutput.cxx b/sc/source/core/data/dpoutput.cxx
new file mode 100644
index 000000000000..63acede160c9
--- /dev/null
+++ b/sc/source/core/data/dpoutput.cxx
@@ -0,0 +1,1961 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dpoutput.cxx,v $
+ * $Revision: 1.17.30.2 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/algitem.hxx>
+#include <svx/boxitem.hxx>
+#include <svx/brshitem.hxx>
+#include <svx/wghtitem.hxx>
+#include <unotools/transliterationwrapper.hxx>
+
+#include "dpoutput.hxx"
+#include "dptabsrc.hxx"
+#include "dpcachetable.hxx"
+#include "document.hxx"
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "markdata.hxx"
+#include "attrib.hxx"
+#include "formula/errorcodes.hxx" // errNoValue
+#include "miscuno.hxx"
+#include "globstr.hrc"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "collect.hxx"
+#include "scresid.hxx"
+#include "unonames.hxx"
+#include "sc.hrc"
+
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
+#include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
+#include <com/sun/star/sheet/DataPilotTablePositionType.hpp>
+#include <com/sun/star/sheet/DataPilotTableResultData.hpp>
+#include <com/sun/star/sheet/DataResultFlags.hpp>
+#include <com/sun/star/sheet/GeneralFunction.hpp>
+#include <com/sun/star/sheet/MemberResultFlags.hpp>
+#include <com/sun/star/sheet/TableFilterField.hpp>
+#include <com/sun/star/sheet/XDataPilotMemberResults.hpp>
+#include <com/sun/star/sheet/XDataPilotResults.hpp>
+#include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
+#include <com/sun/star/sheet/XLevelsSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <vector>
+
+using namespace com::sun::star;
+using ::std::vector;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::sheet::DataPilotTablePositionData;
+using ::com::sun::star::sheet::DataPilotTableResultData;
+using ::com::sun::star::uno::makeAny;
+using ::com::sun::star::uno::Any;
+using ::rtl::OUString;
+
+// -----------------------------------------------------------------------
+
+//! move to a header file
+//! use names from unonames.hxx?
+#define DP_PROP_FUNCTION "Function"
+#define DP_PROP_ORIENTATION "Orientation"
+#define DP_PROP_POSITION "Position"
+#define DP_PROP_USEDHIERARCHY "UsedHierarchy"
+#define DP_PROP_DATADESCR "DataDescription"
+#define DP_PROP_ISDATALAYOUT "IsDataLayoutDimension"
+#define DP_PROP_NUMBERFORMAT "NumberFormat"
+#define DP_PROP_FILTER "Filter"
+#define DP_PROP_COLUMNGRAND "ColumnGrand"
+#define DP_PROP_ROWGRAND "RowGrand"
+#define DP_PROP_SUBTOTALS "SubTotals"
+
+// -----------------------------------------------------------------------
+
+//! dynamic!!!
+#define SC_DPOUT_MAXLEVELS 256
+
+
+struct ScDPOutLevelData
+{
+ long nDim;
+ long nHier;
+ long nLevel;
+ long nDimPos;
+ uno::Sequence<sheet::MemberResult> aResult;
+ String aCaption;
+
+ ScDPOutLevelData() { nDim = nHier = nLevel = nDimPos = -1; }
+
+ BOOL operator<(const ScDPOutLevelData& r) const
+ { return nDimPos<r.nDimPos || ( nDimPos==r.nDimPos && nHier<r.nHier ) ||
+ ( nDimPos==r.nDimPos && nHier==r.nHier && nLevel<r.nLevel ); }
+
+ void Swap(ScDPOutLevelData& r)
+//! { ScDPOutLevelData aTemp = r; r = *this; *this = aTemp; }
+ { ScDPOutLevelData aTemp; aTemp = r; r = *this; *this = aTemp; }
+
+ //! bug (73840) in uno::Sequence - copy and then assign doesn't work!
+};
+
+// -----------------------------------------------------------------------
+
+void lcl_SetStyleById( ScDocument* pDoc, SCTAB nTab,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ USHORT nStrId )
+{
+ if ( nCol1 > nCol2 || nRow1 > nRow2 )
+ {
+ DBG_ERROR("SetStyleById: invalid range");
+ return;
+ }
+
+ String aStyleName = ScGlobal::GetRscString( nStrId );
+ ScStyleSheetPool* pStlPool = pDoc->GetStyleSheetPool();
+ ScStyleSheet* pStyle = (ScStyleSheet*) pStlPool->Find( aStyleName, SFX_STYLE_FAMILY_PARA );
+ if (!pStyle)
+ {
+ // create new style (was in ScPivot::SetStyle)
+
+ pStyle = (ScStyleSheet*) &pStlPool->Make( aStyleName, SFX_STYLE_FAMILY_PARA,
+ SFXSTYLEBIT_USERDEF );
+ pStyle->SetParent( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
+ SfxItemSet& rSet = pStyle->GetItemSet();
+ if ( nStrId==STR_PIVOT_STYLE_RESULT || nStrId==STR_PIVOT_STYLE_TITLE )
+ rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
+ if ( nStrId==STR_PIVOT_STYLE_CATEGORY || nStrId==STR_PIVOT_STYLE_TITLE )
+ rSet.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
+ }
+
+ pDoc->ApplyStyleAreaTab( nCol1, nRow1, nCol2, nRow2, nTab, *pStyle );
+}
+
+void lcl_SetFrame( ScDocument* pDoc, SCTAB nTab,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ USHORT nWidth )
+{
+ SvxBorderLine aLine;
+ aLine.SetOutWidth(nWidth);
+ SvxBoxItem aBox( ATTR_BORDER );
+ aBox.SetLine(&aLine, BOX_LINE_LEFT);
+ aBox.SetLine(&aLine, BOX_LINE_TOP);
+ aBox.SetLine(&aLine, BOX_LINE_RIGHT);
+ aBox.SetLine(&aLine, BOX_LINE_BOTTOM);
+ SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
+ aBoxInfo.SetValid(VALID_HORI,FALSE);
+ aBoxInfo.SetValid(VALID_VERT,FALSE);
+ aBoxInfo.SetValid(VALID_DISTANCE,FALSE);
+
+ pDoc->ApplyFrameAreaTab( ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab ), &aBox, &aBoxInfo );
+}
+
+// -----------------------------------------------------------------------
+
+void lcl_FillNumberFormats( UINT32*& rFormats, long& rCount,
+ const uno::Reference<sheet::XDataPilotMemberResults>& xLevRes,
+ const uno::Reference<container::XIndexAccess>& xDims )
+{
+ if ( rFormats )
+ return; // already set
+
+ // xLevRes is from the data layout dimension
+ //! use result sequence from ScDPOutLevelData!
+
+ uno::Sequence<sheet::MemberResult> aResult = xLevRes->getResults();
+
+ long nSize = aResult.getLength();
+ if (nSize)
+ {
+ // get names/formats for all data dimensions
+ //! merge this with the loop to collect ScDPOutLevelData?
+
+ String aDataNames[SC_DPOUT_MAXLEVELS];
+ UINT32 nDataFormats[SC_DPOUT_MAXLEVELS];
+ long nDataCount = 0;
+ BOOL bAnySet = FALSE;
+
+ long nDimCount = xDims->getCount();
+ for (long nDim=0; nDim<nDimCount; nDim++)
+ {
+ uno::Reference<uno::XInterface> xDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ uno::Reference<container::XNamed> xDimName( xDim, uno::UNO_QUERY );
+ if ( xDimProp.is() && xDimName.is() )
+ {
+ sheet::DataPilotFieldOrientation eDimOrient =
+ (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
+ sheet::DataPilotFieldOrientation_HIDDEN );
+ if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
+ {
+ aDataNames[nDataCount] = String( xDimName->getName() );
+ long nFormat = ScUnoHelpFunctions::GetLongProperty(
+ xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_NUMBERFORMAT) );
+ nDataFormats[nDataCount] = nFormat;
+ if ( nFormat != 0 )
+ bAnySet = TRUE;
+ ++nDataCount;
+ }
+ }
+ }
+
+ if ( bAnySet ) // forget everything if all formats are 0 (or no data dimensions)
+ {
+ const sheet::MemberResult* pArray = aResult.getConstArray();
+
+ String aName;
+ UINT32* pNumFmt = new UINT32[nSize];
+ if (nDataCount == 1)
+ {
+ // only one data dimension -> use its numberformat everywhere
+ long nFormat = nDataFormats[0];
+ for (long nPos=0; nPos<nSize; nPos++)
+ pNumFmt[nPos] = nFormat;
+ }
+ else
+ {
+ for (long nPos=0; nPos<nSize; nPos++)
+ {
+ // if CONTINUE bit is set, keep previous name
+ //! keep number format instead!
+ if ( !(pArray[nPos].Flags & sheet::MemberResultFlags::CONTINUE) )
+ aName = String( pArray[nPos].Name );
+
+ UINT32 nFormat = 0;
+ for (long i=0; i<nDataCount; i++)
+ if (aName == aDataNames[i]) //! search more efficiently?
+ {
+ nFormat = nDataFormats[i];
+ break;
+ }
+ pNumFmt[nPos] = nFormat;
+ }
+ }
+
+ rFormats = pNumFmt;
+ rCount = nSize;
+ }
+ }
+}
+
+UINT32 lcl_GetFirstNumberFormat( const uno::Reference<container::XIndexAccess>& xDims )
+{
+ long nDimCount = xDims->getCount();
+ for (long nDim=0; nDim<nDimCount; nDim++)
+ {
+ uno::Reference<uno::XInterface> xDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ if ( xDimProp.is() )
+ {
+ sheet::DataPilotFieldOrientation eDimOrient =
+ (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
+ sheet::DataPilotFieldOrientation_HIDDEN );
+ if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
+ {
+ long nFormat = ScUnoHelpFunctions::GetLongProperty(
+ xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_NUMBERFORMAT) );
+
+ return nFormat; // use format from first found data dimension
+ }
+ }
+ }
+
+ return 0; // none found
+}
+
+void lcl_SortFields( ScDPOutLevelData* pFields, long nFieldCount )
+{
+ for (long i=0; i+1<nFieldCount; i++)
+ {
+ for (long j=0; j+i+1<nFieldCount; j++)
+ if ( pFields[j+1] < pFields[j] )
+ pFields[j].Swap( pFields[j+1] );
+ }
+}
+
+BOOL lcl_MemberEmpty( const uno::Sequence<sheet::MemberResult>& rSeq )
+{
+ // used to skip levels that have no members
+
+ long nLen = rSeq.getLength();
+ const sheet::MemberResult* pArray = rSeq.getConstArray();
+ for (long i=0; i<nLen; i++)
+ if (pArray[i].Flags & sheet::MemberResultFlags::HASMEMBER)
+ return FALSE;
+
+ return TRUE; // no member data -> empty
+}
+
+uno::Sequence<sheet::MemberResult> lcl_GetSelectedPageAsResult( const uno::Reference<beans::XPropertySet>& xDimProp )
+{
+ uno::Sequence<sheet::MemberResult> aRet;
+ if ( xDimProp.is() )
+ {
+ try
+ {
+ //! merge with ScDPDimension::setPropertyValue?
+
+ uno::Any aValue = xDimProp->getPropertyValue( rtl::OUString::createFromAscii(DP_PROP_FILTER) );
+
+ uno::Sequence<sheet::TableFilterField> aSeq;
+ if (aValue >>= aSeq)
+ {
+ if ( aSeq.getLength() == 1 )
+ {
+ const sheet::TableFilterField& rField = aSeq[0];
+ if ( rField.Field == 0 && rField.Operator == sheet::FilterOperator_EQUAL && !rField.IsNumeric )
+ {
+ rtl::OUString aSelectedPage( rField.StringValue );
+ //! different name/caption string?
+ sheet::MemberResult aResult( aSelectedPage, aSelectedPage, 0 );
+ aRet = uno::Sequence<sheet::MemberResult>( &aResult, 1 );
+ }
+ }
+ // else return empty sequence
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ // recent addition - allow source to not handle it (no error)
+ }
+ }
+ return aRet;
+}
+
+ScDPOutput::ScDPOutput( ScDocument* pD, const uno::Reference<sheet::XDimensionsSupplier>& xSrc,
+ const ScAddress& rPos, BOOL bFilter ) :
+ pDoc( pD ),
+ xSource( xSrc ),
+ aStartPos( rPos ),
+ bDoFilter( bFilter ),
+ bResultsError( FALSE ),
+ pColNumFmt( NULL ),
+ pRowNumFmt( NULL ),
+ nColFmtCount( 0 ),
+ nRowFmtCount( 0 ),
+ nSingleNumFmt( 0 ),
+ bSizesValid( FALSE ),
+ bSizeOverflow( FALSE )
+{
+ nTabStartCol = nMemberStartCol = nDataStartCol = nTabEndCol = 0;
+ nTabStartRow = nMemberStartRow = nDataStartRow = nTabEndRow = 0;
+
+ pColFields = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS];
+ pRowFields = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS];
+ pPageFields = new ScDPOutLevelData[SC_DPOUT_MAXLEVELS];
+ nColFieldCount = 0;
+ nRowFieldCount = 0;
+ nPageFieldCount = 0;
+
+ uno::Reference<sheet::XDataPilotResults> xResult( xSource, uno::UNO_QUERY );
+ if ( xSource.is() && xResult.is() )
+ {
+ // get dimension results:
+
+ uno::Reference<container::XIndexAccess> xDims =
+ new ScNameToIndexAccess( xSource->getDimensions() );
+ long nDimCount = xDims->getCount();
+ for (long nDim=0; nDim<nDimCount; nDim++)
+ {
+ uno::Reference<uno::XInterface> xDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ uno::Reference<sheet::XHierarchiesSupplier> xDimSupp( xDim, uno::UNO_QUERY );
+ if ( xDimProp.is() && xDimSupp.is() )
+ {
+ sheet::DataPilotFieldOrientation eDimOrient =
+ (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
+ sheet::DataPilotFieldOrientation_HIDDEN );
+ long nDimPos = ScUnoHelpFunctions::GetLongProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_POSITION) );
+ BOOL bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(
+ xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+
+ if ( eDimOrient != sheet::DataPilotFieldOrientation_HIDDEN )
+ {
+ uno::Reference<container::XIndexAccess> xHiers =
+ new ScNameToIndexAccess( xDimSupp->getHierarchies() );
+ long nHierarchy = ScUnoHelpFunctions::GetLongProperty(
+ xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY) );
+ if ( nHierarchy >= xHiers->getCount() )
+ nHierarchy = 0;
+
+ uno::Reference<uno::XInterface> xHier =
+ ScUnoHelpFunctions::AnyToInterface(
+ xHiers->getByIndex(nHierarchy) );
+ uno::Reference<sheet::XLevelsSupplier> xHierSupp( xHier, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XIndexAccess> xLevels =
+ new ScNameToIndexAccess( xHierSupp->getLevels() );
+ long nLevCount = xLevels->getCount();
+ for (long nLev=0; nLev<nLevCount; nLev++)
+ {
+ uno::Reference<uno::XInterface> xLevel =
+ ScUnoHelpFunctions::AnyToInterface(
+ xLevels->getByIndex(nLev) );
+ uno::Reference<container::XNamed> xLevNam( xLevel, uno::UNO_QUERY );
+ uno::Reference<sheet::XDataPilotMemberResults> xLevRes(
+ xLevel, uno::UNO_QUERY );
+ if ( xLevNam.is() && xLevRes.is() )
+ {
+ String aCaption = String(xLevNam->getName()); //! Caption...
+ switch ( eDimOrient )
+ {
+ case sheet::DataPilotFieldOrientation_COLUMN:
+ pColFields[nColFieldCount].nDim = nDim;
+ pColFields[nColFieldCount].nHier = nHierarchy;
+ pColFields[nColFieldCount].nLevel = nLev;
+ pColFields[nColFieldCount].nDimPos = nDimPos;
+ pColFields[nColFieldCount].aResult = xLevRes->getResults();
+ pColFields[nColFieldCount].aCaption= aCaption;
+ if (!lcl_MemberEmpty(pColFields[nColFieldCount].aResult))
+ ++nColFieldCount;
+ break;
+ case sheet::DataPilotFieldOrientation_ROW:
+ pRowFields[nRowFieldCount].nDim = nDim;
+ pRowFields[nRowFieldCount].nHier = nHierarchy;
+ pRowFields[nRowFieldCount].nLevel = nLev;
+ pRowFields[nRowFieldCount].nDimPos = nDimPos;
+ pRowFields[nRowFieldCount].aResult = xLevRes->getResults();
+ pRowFields[nRowFieldCount].aCaption= aCaption;
+ if (!lcl_MemberEmpty(pRowFields[nRowFieldCount].aResult))
+ ++nRowFieldCount;
+ break;
+ case sheet::DataPilotFieldOrientation_PAGE:
+ pPageFields[nPageFieldCount].nDim = nDim;
+ pPageFields[nPageFieldCount].nHier = nHierarchy;
+ pPageFields[nPageFieldCount].nLevel = nLev;
+ pPageFields[nPageFieldCount].nDimPos = nDimPos;
+ pPageFields[nPageFieldCount].aResult = lcl_GetSelectedPageAsResult(xDimProp);
+ pPageFields[nPageFieldCount].aCaption= aCaption;
+ // no check on results for page fields
+ ++nPageFieldCount;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ // get number formats from data dimensions
+ if ( bIsDataLayout )
+ {
+ DBG_ASSERT( nLevCount == 1, "data layout: multiple levels?" );
+ if ( eDimOrient == sheet::DataPilotFieldOrientation_COLUMN )
+ lcl_FillNumberFormats( pColNumFmt, nColFmtCount, xLevRes, xDims );
+ else if ( eDimOrient == sheet::DataPilotFieldOrientation_ROW )
+ lcl_FillNumberFormats( pRowNumFmt, nRowFmtCount, xLevRes, xDims );
+ }
+ }
+ }
+ }
+ }
+ else if ( bIsDataLayout )
+ {
+ // data layout dimension is hidden (allowed if there is only one data dimension)
+ // -> use the number format from the first data dimension for all results
+
+ nSingleNumFmt = lcl_GetFirstNumberFormat( xDims );
+ }
+ }
+ }
+ lcl_SortFields( pColFields, nColFieldCount );
+ lcl_SortFields( pRowFields, nRowFieldCount );
+ lcl_SortFields( pPageFields, nPageFieldCount );
+
+ // get data results:
+
+ try
+ {
+ aData = xResult->getResults();
+ }
+ catch (uno::RuntimeException&)
+ {
+ bResultsError = TRUE;
+ }
+ }
+
+ // get "DataDescription" property (may be missing in external sources)
+
+ uno::Reference<beans::XPropertySet> xSrcProp( xSource, uno::UNO_QUERY );
+ if ( xSrcProp.is() )
+ {
+ try
+ {
+ uno::Any aAny = xSrcProp->getPropertyValue(
+ rtl::OUString::createFromAscii(DP_PROP_DATADESCR) );
+ rtl::OUString aUStr;
+ aAny >>= aUStr;
+ aDataDescription = String( aUStr );
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+}
+
+ScDPOutput::~ScDPOutput()
+{
+ delete[] pColFields;
+ delete[] pRowFields;
+ delete[] pPageFields;
+
+ delete[] pColNumFmt;
+ delete[] pRowNumFmt;
+}
+
+void ScDPOutput::SetPosition( const ScAddress& rPos )
+{
+ aStartPos = rPos;
+ bSizesValid = bSizeOverflow = FALSE;
+}
+
+void ScDPOutput::DataCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const sheet::DataResult& rData )
+{
+ long nFlags = rData.Flags;
+ if ( nFlags & sheet::DataResultFlags::ERROR )
+ {
+ pDoc->SetError( nCol, nRow, nTab, errNoValue );
+ }
+ else if ( nFlags & sheet::DataResultFlags::HASDATA )
+ {
+ pDoc->SetValue( nCol, nRow, nTab, rData.Value );
+
+ // use number formats from source
+
+ DBG_ASSERT( bSizesValid, "DataCell: !bSizesValid" );
+ UINT32 nFormat = 0;
+ if ( pColNumFmt )
+ {
+ if ( nCol >= nDataStartCol )
+ {
+ long nIndex = nCol - nDataStartCol;
+ if ( nIndex < nColFmtCount )
+ nFormat = pColNumFmt[nIndex];
+ }
+ }
+ else if ( pRowNumFmt )
+ {
+ if ( nRow >= nDataStartRow )
+ {
+ long nIndex = nRow - nDataStartRow;
+ if ( nIndex < nRowFmtCount )
+ nFormat = pRowNumFmt[nIndex];
+ }
+ }
+ else if ( nSingleNumFmt != 0 )
+ nFormat = nSingleNumFmt; // single format is used everywhere
+ if ( nFormat != 0 )
+ pDoc->ApplyAttr( nCol, nRow, nTab, SfxUInt32Item( ATTR_VALUE_FORMAT, nFormat ) );
+ }
+ else
+ {
+ //pDoc->SetString( nCol, nRow, nTab, EMPTY_STRING );
+ }
+
+ // SubTotal formatting is controlled by headers
+}
+
+void ScDPOutput::HeaderCell( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ const sheet::MemberResult& rData, BOOL bColHeader, long nLevel )
+{
+ long nFlags = rData.Flags;
+ if ( nFlags & sheet::MemberResultFlags::HASMEMBER )
+ {
+ pDoc->SetString( nCol, nRow, nTab, rData.Caption );
+ }
+ else
+ {
+ //pDoc->SetString( nCol, nRow, nTab, EMPTY_STRING );
+ }
+
+ if ( nFlags & sheet::MemberResultFlags::SUBTOTAL )
+ {
+// SvxWeightItem aItem( WEIGHT_BOLD ); // weight is in the style
+
+ //! limit frames to horizontal or vertical?
+ if (bColHeader)
+ {
+ lcl_SetFrame( pDoc,nTab, nCol,nMemberStartRow+(SCROW)nLevel, nCol,nTabEndRow, 20 );
+ lcl_SetStyleById( pDoc,nTab, nCol,nMemberStartRow+(SCROW)nLevel, nCol,nDataStartRow-1,
+ STR_PIVOT_STYLE_TITLE );
+ lcl_SetStyleById( pDoc,nTab, nCol,nDataStartRow, nCol,nTabEndRow,
+ STR_PIVOT_STYLE_RESULT );
+ }
+ else
+ {
+ lcl_SetFrame( pDoc,nTab, nMemberStartCol+(SCCOL)nLevel,nRow, nTabEndCol,nRow, 20 );
+ lcl_SetStyleById( pDoc,nTab, nMemberStartCol+(SCCOL)nLevel,nRow, nDataStartCol-1,nRow,
+ STR_PIVOT_STYLE_TITLE );
+ lcl_SetStyleById( pDoc,nTab, nDataStartCol,nRow, nTabEndCol,nRow,
+ STR_PIVOT_STYLE_RESULT );
+ }
+ }
+}
+
+void ScDPOutput::FieldCell( SCCOL nCol, SCROW nRow, SCTAB nTab, const String& rCaption, BOOL bFrame )
+{
+ pDoc->SetString( nCol, nRow, nTab, rCaption );
+ if (bFrame)
+ lcl_SetFrame( pDoc,nTab, nCol,nRow, nCol,nRow, 20 );
+
+ // Button
+ pDoc->ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr(SC_MF_BUTTON) );
+
+ lcl_SetStyleById( pDoc,nTab, nCol,nRow, nCol,nRow, STR_PIVOT_STYLE_FIELDNAME );
+}
+
+void lcl_DoFilterButton( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ pDoc->SetString( nCol, nRow, nTab, ScGlobal::GetRscString(STR_CELL_FILTER) );
+ pDoc->ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr(SC_MF_BUTTON) );
+}
+
+void ScDPOutput::CalcSizes()
+{
+ if (!bSizesValid)
+ {
+ // get column size of data from first row
+ //! allow different sizes (and clear following areas) ???
+
+ nRowCount = aData.getLength();
+ const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
+ nColCount = nRowCount ? ( pRowAry[0].getLength() ) : 0;
+ nHeaderSize = 1; // one row for field names
+
+ // calculate output positions and sizes
+
+ long nPageSize = 0; //! use page fields!
+ if ( bDoFilter || nPageFieldCount )
+ {
+ nPageSize += nPageFieldCount + 1; // plus one empty row
+ if ( bDoFilter )
+ ++nPageSize; // filter button above the page fields
+ }
+
+ if ( aStartPos.Col() + nRowFieldCount + nColCount - 1 > MAXCOL ||
+ aStartPos.Row() + nPageSize + nHeaderSize + nColFieldCount + nRowCount > MAXROW )
+ {
+ bSizeOverflow = TRUE;
+ }
+
+ nTabStartCol = aStartPos.Col();
+ nTabStartRow = aStartPos.Row() + (SCROW)nPageSize; // below page fields
+ nMemberStartCol = nTabStartCol;
+ nMemberStartRow = nTabStartRow + (SCROW) nHeaderSize;
+ nDataStartCol = nMemberStartCol + (SCCOL)nRowFieldCount;
+ nDataStartRow = nMemberStartRow + (SCROW)nColFieldCount;
+ if ( nColCount > 0 )
+ nTabEndCol = nDataStartCol + (SCCOL)nColCount - 1;
+ else
+ nTabEndCol = nDataStartCol; // single column will remain empty
+ // if page fields are involved, include the page selection cells
+ if ( nPageFieldCount > 0 && nTabEndCol < nTabStartCol + 1 )
+ nTabEndCol = nTabStartCol + 1;
+ if ( nRowCount > 0 )
+ nTabEndRow = nDataStartRow + (SCROW)nRowCount - 1;
+ else
+ nTabEndRow = nDataStartRow; // single row will remain empty
+ bSizesValid = TRUE;
+ }
+}
+
+sal_Int32 ScDPOutput::GetPositionType(const ScAddress& rPos)
+{
+ using namespace ::com::sun::star::sheet;
+
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+ if ( nTab != aStartPos.Tab() )
+ return DataPilotTablePositionType::NOT_IN_TABLE;
+
+ CalcSizes();
+
+ // Make sure the cursor is within the table.
+ if (nCol < nTabStartCol || nRow < nTabStartRow || nCol > nTabEndCol || nRow > nTabEndRow)
+ return DataPilotTablePositionType::NOT_IN_TABLE;
+
+ // test for result data area.
+ if (nCol >= nDataStartCol && nCol <= nTabEndCol && nRow >= nDataStartRow && nRow <= nTabEndRow)
+ return DataPilotTablePositionType::RESULT;
+
+ bool bInColHeader = (nRow >= nTabStartRow && nRow < nDataStartRow);
+ bool bInRowHeader = (nCol >= nTabStartCol && nCol < nDataStartCol);
+
+ if (bInColHeader && bInRowHeader)
+ // probably in that ugly little box at the upper-left corner of the table.
+ return DataPilotTablePositionType::OTHER;
+
+ if (bInColHeader)
+ {
+ if (nRow == nTabStartRow)
+ // first row in the column header area is always used for column
+ // field buttons.
+ return DataPilotTablePositionType::OTHER;
+
+ return DataPilotTablePositionType::COLUMN_HEADER;
+ }
+
+ if (bInRowHeader)
+ return DataPilotTablePositionType::ROW_HEADER;
+
+ return DataPilotTablePositionType::OTHER;
+}
+
+void ScDPOutput::Output()
+{
+ long nField;
+ SCTAB nTab = aStartPos.Tab();
+ const uno::Sequence<sheet::DataResult>* pRowAry = aData.getConstArray();
+
+ // calculate output positions and sizes
+
+ CalcSizes();
+ if ( bSizeOverflow || bResultsError ) // does output area exceed sheet limits?
+ return; // nothing
+
+ // clear whole (new) output area
+ //! when modifying table, clear old area
+ //! include IDF_OBJECTS ???
+ pDoc->DeleteAreaTab( aStartPos.Col(), aStartPos.Row(), nTabEndCol, nTabEndRow, nTab, IDF_ALL );
+
+ if ( bDoFilter )
+ lcl_DoFilterButton( pDoc, aStartPos.Col(), aStartPos.Row(), nTab );
+
+ // output page fields:
+
+ for (nField=0; nField<nPageFieldCount; nField++)
+ {
+ SCCOL nHdrCol = aStartPos.Col();
+ SCROW nHdrRow = aStartPos.Row() + nField + ( bDoFilter ? 1 : 0 );
+ // draw without frame for consistency with filter button:
+ FieldCell( nHdrCol, nHdrRow, nTab, pPageFields[nField].aCaption, FALSE );
+ SCCOL nFldCol = nHdrCol + 1;
+
+ String aPageValue;
+ if ( pPageFields[nField].aResult.getLength() == 1 )
+ aPageValue = pPageFields[nField].aResult[0].Caption;
+ else
+ aPageValue = String( ScResId( SCSTR_ALL ) ); //! separate string?
+
+ pDoc->SetString( nFldCol, nHdrRow, nTab, aPageValue );
+
+ lcl_SetFrame( pDoc,nTab, nFldCol,nHdrRow, nFldCol,nHdrRow, 20 );
+ pDoc->ApplyAttr( nFldCol, nHdrRow, nTab, ScMergeFlagAttr(SC_MF_AUTO) );
+ //! which style?
+ }
+
+ // data description
+ // (may get overwritten by first row field)
+
+ String aDesc = aDataDescription;
+ if ( !aDesc.Len() )
+ {
+ //! use default string ("result") ?
+ }
+ pDoc->SetString( nTabStartCol, nTabStartRow, nTab, aDesc );
+
+ // set STR_PIVOT_STYLE_INNER for whole data area (subtotals are overwritten)
+
+ if ( nDataStartRow > nTabStartRow )
+ lcl_SetStyleById( pDoc, nTab, nTabStartCol, nTabStartRow, nTabEndCol, nDataStartRow-1,
+ STR_PIVOT_STYLE_TOP );
+ lcl_SetStyleById( pDoc, nTab, nDataStartCol, nDataStartRow, nTabEndCol, nTabEndRow,
+ STR_PIVOT_STYLE_INNER );
+
+ // output column headers:
+
+ for (nField=0; nField<nColFieldCount; nField++)
+ {
+ SCCOL nHdrCol = nDataStartCol + (SCCOL)nField; //! check for overflow
+ FieldCell( nHdrCol, nTabStartRow, nTab, pColFields[nField].aCaption );
+
+ SCROW nRowPos = nMemberStartRow + (SCROW)nField; //! check for overflow
+ const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].aResult;
+ const sheet::MemberResult* pArray = rSequence.getConstArray();
+ long nThisColCount = rSequence.getLength();
+ DBG_ASSERT( nThisColCount == nColCount, "count mismatch" ); //! ???
+ for (long nCol=0; nCol<nThisColCount; nCol++)
+ {
+ SCCOL nColPos = nDataStartCol + (SCCOL)nCol; //! check for overflow
+ HeaderCell( nColPos, nRowPos, nTab, pArray[nCol], TRUE, nField );
+ if ( ( pArray[nCol].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
+ !( pArray[nCol].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
+ {
+ if ( nField+1 < nColFieldCount )
+ {
+ long nEnd = nCol;
+ while ( nEnd+1 < nThisColCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
+ ++nEnd;
+ SCCOL nEndColPos = nDataStartCol + (SCCOL)nEnd; //! check for overflow
+ lcl_SetFrame( pDoc,nTab, nColPos,nRowPos, nEndColPos,nRowPos, 20 );
+ lcl_SetFrame( pDoc,nTab, nColPos,nRowPos, nEndColPos,nTabEndRow, 20 );
+
+ lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nEndColPos,nDataStartRow-1, STR_PIVOT_STYLE_CATEGORY );
+ }
+ else
+ lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nColPos,nDataStartRow-1, STR_PIVOT_STYLE_CATEGORY );
+ }
+ }
+ }
+
+ // output row headers:
+
+ for (nField=0; nField<nRowFieldCount; nField++)
+ {
+ SCCOL nHdrCol = nTabStartCol + (SCCOL)nField; //! check for overflow
+ SCROW nHdrRow = nDataStartRow - 1;
+ FieldCell( nHdrCol, nHdrRow, nTab, pRowFields[nField].aCaption );
+
+ SCCOL nColPos = nMemberStartCol + (SCCOL)nField; //! check for overflow
+ const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].aResult;
+ const sheet::MemberResult* pArray = rSequence.getConstArray();
+ long nThisRowCount = rSequence.getLength();
+ DBG_ASSERT( nThisRowCount == nRowCount, "count mismatch" ); //! ???
+ for (long nRow=0; nRow<nThisRowCount; nRow++)
+ {
+ SCROW nRowPos = nDataStartRow + (SCROW)nRow; //! check for overflow
+ HeaderCell( nColPos, nRowPos, nTab, pArray[nRow], FALSE, nField );
+ if ( ( pArray[nRow].Flags & sheet::MemberResultFlags::HASMEMBER ) &&
+ !( pArray[nRow].Flags & sheet::MemberResultFlags::SUBTOTAL ) )
+ {
+ if ( nField+1 < nRowFieldCount )
+ {
+ long nEnd = nRow;
+ while ( nEnd+1 < nThisRowCount && ( pArray[nEnd+1].Flags & sheet::MemberResultFlags::CONTINUE ) )
+ ++nEnd;
+ SCROW nEndRowPos = nDataStartRow + (SCROW)nEnd; //! check for overflow
+ lcl_SetFrame( pDoc,nTab, nColPos,nRowPos, nColPos,nEndRowPos, 20 );
+ lcl_SetFrame( pDoc,nTab, nColPos,nRowPos, nTabEndCol,nEndRowPos, 20 );
+
+ lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nEndRowPos, STR_PIVOT_STYLE_CATEGORY );
+ }
+ else
+ lcl_SetStyleById( pDoc, nTab, nColPos,nRowPos, nDataStartCol-1,nRowPos, STR_PIVOT_STYLE_CATEGORY );
+ }
+ }
+ }
+
+ // output data results:
+
+ for (long nRow=0; nRow<nRowCount; nRow++)
+ {
+ SCROW nRowPos = nDataStartRow + (SCROW)nRow; //! check for overflow
+ const sheet::DataResult* pColAry = pRowAry[nRow].getConstArray();
+ long nThisColCount = pRowAry[nRow].getLength();
+ DBG_ASSERT( nThisColCount == nColCount, "count mismatch" ); //! ???
+ for (long nCol=0; nCol<nThisColCount; nCol++)
+ {
+ SCCOL nColPos = nDataStartCol + (SCCOL)nCol; //! check for overflow
+ DataCell( nColPos, nRowPos, nTab, pColAry[nCol] );
+ }
+ }
+
+ // frame around the whole table
+
+ lcl_SetFrame( pDoc,nTab, nDataStartCol,nDataStartRow, nTabEndCol,nTabEndRow, 20 );
+ if ( nDataStartCol > nMemberStartCol )
+ lcl_SetFrame( pDoc,nTab, nMemberStartCol,nDataStartRow, nDataStartCol-1,nTabEndRow, 20 );
+ if ( nDataStartRow > nMemberStartRow )
+ lcl_SetFrame( pDoc,nTab, nDataStartCol,nMemberStartRow, nTabEndCol,nDataStartRow-1, 20 );
+
+ lcl_SetFrame( pDoc,nTab, nTabStartCol,nTabStartRow, nTabEndCol,nTabEndRow, 40 );
+}
+
+ScRange ScDPOutput::GetOutputRange( sal_Int32 nRegionType )
+{
+ using namespace ::com::sun::star::sheet;
+
+ CalcSizes();
+
+// fprintf(stdout, "ScDPOutput::GetOutputRange: aStartPos = (%ld, %d)\n", aStartPos.Row(), aStartPos.Col());fflush(stdout);
+// fprintf(stdout, "ScDPOutput::GetOutputRange: nTabStart (Row = %ld, Col = %ld)\n", nTabStartRow, nTabStartCol);fflush(stdout);
+// fprintf(stdout, "ScDPOutput::GetOutputRange: nMemberStart (Row = %ld, Col = %ld)\n", nMemberStartRow, nMemberStartCol);fflush(stdout);
+// fprintf(stdout, "ScDPOutput::GetOutputRange: nDataStart (Row = %ld, Col = %ld)\n", nDataStartRow, nDataStartCol);fflush(stdout);
+// fprintf(stdout, "ScDPOutput::GetOutputRange: nTabEnd (Row = %ld, Col = %ld)\n", nTabEndRow, nTabStartCol);fflush(stdout);
+
+ SCTAB nTab = aStartPos.Tab();
+ switch (nRegionType)
+ {
+ case DataPilotOutputRangeType::RESULT:
+ return ScRange(nDataStartCol, nDataStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
+ case DataPilotOutputRangeType::TABLE:
+ return ScRange(aStartPos.Col(), nTabStartRow, nTab, nTabEndCol, nTabEndRow, nTab);
+ default:
+ DBG_ASSERT(nRegionType == DataPilotOutputRangeType::WHOLE, "ScDPOutput::GetOutputRange: unknown region type");
+ break;
+ }
+ return ScRange(aStartPos.Col(), aStartPos.Row(), nTab, nTabEndCol, nTabEndRow, nTab);
+}
+
+BOOL ScDPOutput::HasError()
+{
+ CalcSizes();
+
+ return bSizeOverflow || bResultsError;
+}
+
+long ScDPOutput::GetHeaderRows()
+{
+ return nPageFieldCount + ( bDoFilter ? 1 : 0 );
+}
+
+void ScDPOutput::GetMemberResultNames( ScStrCollection& rNames, long nDimension )
+{
+ // Return the list of all member names in a dimension's MemberResults.
+ // Only the dimension has to be compared because this is only used with table data,
+ // where each dimension occurs only once.
+
+ uno::Sequence<sheet::MemberResult> aMemberResults;
+ bool bFound = false;
+ long nField;
+
+ // look in column fields
+
+ for (nField=0; nField<nColFieldCount && !bFound; nField++)
+ if ( pColFields[nField].nDim == nDimension )
+ {
+ aMemberResults = pColFields[nField].aResult;
+ bFound = true;
+ }
+
+ // look in row fields
+
+ for (nField=0; nField<nRowFieldCount && !bFound; nField++)
+ if ( pRowFields[nField].nDim == nDimension )
+ {
+ aMemberResults = pRowFields[nField].aResult;
+ bFound = true;
+ }
+
+ // collect the member names
+
+ if ( bFound )
+ {
+ const sheet::MemberResult* pArray = aMemberResults.getConstArray();
+ long nResultCount = aMemberResults.getLength();
+
+ for (long nItem=0; nItem<nResultCount; nItem++)
+ {
+ if ( pArray[nItem].Flags & sheet::MemberResultFlags::HASMEMBER )
+ {
+ StrData* pNew = new StrData( pArray[nItem].Name );
+ if ( !rNames.Insert( pNew ) )
+ delete pNew;
+ }
+ }
+ }
+}
+
+
+void ScDPOutput::GetPositionData(const ScAddress& rPos, DataPilotTablePositionData& rPosData)
+{
+ using namespace ::com::sun::star::sheet;
+
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+ if ( nTab != aStartPos.Tab() )
+ return; // wrong sheet
+
+ // calculate output positions and sizes
+
+ CalcSizes();
+
+ rPosData.PositionType = GetPositionType(rPos);
+ switch (rPosData.PositionType)
+ {
+ case DataPilotTablePositionType::RESULT:
+ {
+ vector<DataPilotFieldFilter> aFilters;
+ GetDataResultPositionData(aFilters, rPos);
+ sal_Int32 nSize = aFilters.size();
+
+ DataPilotTableResultData aResData;
+ aResData.FieldFilters.realloc(nSize);
+ for (sal_Int32 i = 0; i < nSize; ++i)
+ aResData.FieldFilters[i] = aFilters[i];
+
+ aResData.DataFieldIndex = 0;
+ Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
+ if (xPropSet.is())
+ {
+ sal_Int32 nDataFieldCount = 0;
+ Any any = xPropSet->getPropertyValue(rtl::OUString::createFromAscii("DataFieldCount"));
+ if ((any >>= nDataFieldCount) && nDataFieldCount > 0)
+ aResData.DataFieldIndex = (nRow - nDataStartRow) % nDataFieldCount;
+ }
+
+ // Copy appropriate DataResult object from the cached sheet::DataResult table.
+ if (aData.getLength() > nRow - nDataStartRow &&
+ aData[nRow-nDataStartRow].getLength() > nCol-nDataStartCol)
+ aResData.Result = aData[nRow-nDataStartRow][nCol-nDataStartCol];
+
+ rPosData.PositionData = makeAny(aResData);
+ return;
+ }
+ case DataPilotTablePositionType::COLUMN_HEADER:
+ {
+ long nField = nRow - nTabStartRow - 1; // 1st line is used for the buttons
+ if (nField < 0)
+ break;
+
+ const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nField].aResult;
+ if (rSequence.getLength() == 0)
+ break;
+ const sheet::MemberResult* pArray = rSequence.getConstArray();
+
+ long nItem = nCol - nDataStartCol;
+ // get origin of "continue" fields
+ while (nItem > 0 && ( pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
+ --nItem;
+
+ if (nItem < 0)
+ break;
+
+ DataPilotTableHeaderData aHeaderData;
+ aHeaderData.MemberName = OUString(pArray[nItem].Name);
+ aHeaderData.Flags = pArray[nItem].Flags;
+ aHeaderData.Dimension = static_cast<sal_Int32>(pColFields[nField].nDim);
+ aHeaderData.Hierarchy = static_cast<sal_Int32>(pColFields[nField].nHier);
+ aHeaderData.Level = static_cast<sal_Int32>(pColFields[nField].nLevel);
+
+ rPosData.PositionData = makeAny(aHeaderData);
+ return;
+ }
+ case DataPilotTablePositionType::ROW_HEADER:
+ {
+ long nField = nCol - nTabStartCol;
+ if (nField < 0)
+ break;
+
+ const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nField].aResult;
+ if (rSequence.getLength() == 0)
+ break;
+ const sheet::MemberResult* pArray = rSequence.getConstArray();
+
+ long nItem = nRow - nDataStartRow;
+ // get origin of "continue" fields
+ while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
+ --nItem;
+
+ if (nItem < 0)
+ break;
+
+ DataPilotTableHeaderData aHeaderData;
+ aHeaderData.MemberName = OUString(pArray[nItem].Name);
+ aHeaderData.Flags = pArray[nItem].Flags;
+ aHeaderData.Dimension = static_cast<sal_Int32>(pRowFields[nField].nDim);
+ aHeaderData.Hierarchy = static_cast<sal_Int32>(pRowFields[nField].nHier);
+ aHeaderData.Level = static_cast<sal_Int32>(pRowFields[nField].nLevel);
+
+ rPosData.PositionData = makeAny(aHeaderData);
+ return;
+ }
+ }
+}
+
+bool ScDPOutput::GetDataResultPositionData(vector<sheet::DataPilotFieldFilter>& rFilters, const ScAddress& rPos)
+{
+ // Check to make sure there is at least one data field.
+ Reference<beans::XPropertySet> xPropSet(xSource, UNO_QUERY);
+ if (!xPropSet.is())
+ return false;
+
+ sal_Int32 nDataFieldCount = 0;
+ Any any = xPropSet->getPropertyValue(rtl::OUString::createFromAscii("DataFieldCount"));
+ if (!(any >>= nDataFieldCount) || nDataFieldCount == 0)
+ // No data field is present in this datapilot table.
+ return false;
+
+ bool bColGrand = bool();
+ any = xPropSet->getPropertyValue(rtl::OUString::createFromAscii(SC_UNO_COLGRAND));
+ if (!(any >>= bColGrand))
+ return false;
+
+ bool bRowGrand = bool();
+ any = xPropSet->getPropertyValue(rtl::OUString::createFromAscii(SC_UNO_ROWGRAND));
+ if (!(any >>= bRowGrand))
+ return false;
+
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+ if ( nTab != aStartPos.Tab() )
+ return false; // wrong sheet
+
+ CalcSizes();
+
+ // test for data area.
+ if (nCol < nDataStartCol || nCol > nTabEndCol || nRow < nDataStartRow || nRow > nTabEndRow)
+ {
+ // Cell is outside the data field area.
+ return false;
+ }
+
+ bool bFilterByCol = !(bColGrand && (nCol == nTabEndCol));
+ bool bFilterByRow = !(bRowGrand && (nRow == nTabEndRow));
+
+ // column fields
+ for (SCCOL nColField = 0; nColField < nColFieldCount && bFilterByCol; ++nColField)
+ {
+ sheet::DataPilotFieldFilter filter;
+ filter.FieldName = pColFields[nColField].aCaption;
+
+ const uno::Sequence<sheet::MemberResult> rSequence = pColFields[nColField].aResult;
+ const sheet::MemberResult* pArray = rSequence.getConstArray();
+
+ DBG_ASSERT(nDataStartCol + rSequence.getLength() - 1 == nTabEndCol, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
+
+ long nItem = nCol - nDataStartCol;
+ // get origin of "continue" fields
+ while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
+ --nItem;
+
+ filter.MatchValue = pArray[nItem].Name;
+ rFilters.push_back(filter);
+ }
+
+ // row fields
+ for (SCROW nRowField = 0; nRowField < nRowFieldCount && bFilterByRow; ++nRowField)
+ {
+ sheet::DataPilotFieldFilter filter;
+ filter.FieldName = pRowFields[nRowField].aCaption;
+
+ const uno::Sequence<sheet::MemberResult> rSequence = pRowFields[nRowField].aResult;
+ const sheet::MemberResult* pArray = rSequence.getConstArray();
+
+ DBG_ASSERT(nDataStartRow + rSequence.getLength() - 1 == nTabEndRow, "ScDPOutput::GetDataFieldCellData: error in geometric assumption");
+
+ long nItem = nRow - nDataStartRow;
+ // get origin of "continue" fields
+ while ( nItem > 0 && (pArray[nItem].Flags & sheet::MemberResultFlags::CONTINUE) )
+ --nItem;
+
+ filter.MatchValue = pArray[nItem].Name;
+ rFilters.push_back(filter);
+ }
+
+ return true;
+}
+
+//
+// helper functions for ScDPOutput::GetPivotData
+//
+
+bool lcl_IsNamedDataField( const ScDPGetPivotDataField& rTarget, const String& rSourceName, const String& rGivenName )
+{
+ // match one of the names, ignoring case
+ return ScGlobal::pTransliteration->isEqual( rTarget.maFieldName, rSourceName ) ||
+ ScGlobal::pTransliteration->isEqual( rTarget.maFieldName, rGivenName );
+}
+
+bool lcl_IsNamedCategoryField( const ScDPGetPivotDataField& rFilter, const ScDPOutLevelData& rField )
+{
+ //! name from source instead of caption?
+ return ScGlobal::pTransliteration->isEqual( rFilter.maFieldName, rField.aCaption );
+}
+
+bool lcl_IsCondition( const sheet::MemberResult& rResultEntry, const ScDPGetPivotDataField& rFilter )
+{
+ //! handle numeric conditions?
+ return ScGlobal::pTransliteration->isEqual( rResultEntry.Name, rFilter.maValStr );
+}
+
+bool lcl_CheckPageField( const ScDPOutLevelData& rField,
+ const std::vector< ScDPGetPivotDataField >& rFilters,
+ std::vector< BOOL >& rFilterUsed )
+{
+ for (SCSIZE nFilterPos = 0; nFilterPos < rFilters.size(); ++nFilterPos)
+ {
+ if ( lcl_IsNamedCategoryField( rFilters[nFilterPos], rField ) )
+ {
+ rFilterUsed[nFilterPos] = TRUE;
+
+ // page field result is empty or the selection as single entry (see lcl_GetSelectedPageAsResult)
+ if ( rField.aResult.getLength() == 1 &&
+ lcl_IsCondition( rField.aResult[0], rFilters[nFilterPos] ) )
+ {
+ return true; // condition matches page selection
+ }
+ else
+ {
+ return false; // no page selection or different entry
+ }
+ }
+ }
+
+ return true; // valid if the page field doesn't have a filter
+}
+
+uno::Sequence<sheet::GeneralFunction> lcl_GetSubTotals(
+ const uno::Reference<sheet::XDimensionsSupplier>& xSource, const ScDPOutLevelData& rField )
+{
+ uno::Sequence<sheet::GeneralFunction> aSubTotals;
+
+ uno::Reference<sheet::XHierarchiesSupplier> xHierSupp;
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ sal_Int32 nIntCount = xIntDims->getCount();
+ if ( rField.nDim < nIntCount )
+ {
+ uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface(
+ xIntDims->getByIndex( rField.nDim ) );
+ xHierSupp = uno::Reference<sheet::XHierarchiesSupplier>( xIntDim, uno::UNO_QUERY );
+ }
+ DBG_ASSERT( xHierSupp.is(), "dimension not found" );
+
+ sal_Int32 nHierCount = 0;
+ uno::Reference<container::XIndexAccess> xHiers;
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
+ xHiers = new ScNameToIndexAccess( xHiersName );
+ nHierCount = xHiers->getCount();
+ }
+ uno::Reference<uno::XInterface> xHier;
+ if ( rField.nHier < nHierCount )
+ xHier = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex( rField.nHier ) );
+ DBG_ASSERT( xHier.is(), "hierarchy not found" );
+
+ sal_Int32 nLevCount = 0;
+ uno::Reference<container::XIndexAccess> xLevels;
+ uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHier, uno::UNO_QUERY );
+ if ( xLevSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xLevsName = xLevSupp->getLevels();
+ xLevels = new ScNameToIndexAccess( xLevsName );
+ nLevCount = xLevels->getCount();
+ }
+ uno::Reference<uno::XInterface> xLevel;
+ if ( rField.nLevel < nLevCount )
+ xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex( rField.nLevel ) );
+ DBG_ASSERT( xLevel.is(), "level not found" );
+
+ uno::Reference<beans::XPropertySet> xLevelProp( xLevel, uno::UNO_QUERY );
+ if ( xLevelProp.is() )
+ {
+ try
+ {
+ uno::Any aValue = xLevelProp->getPropertyValue( rtl::OUString::createFromAscii(DP_PROP_SUBTOTALS) );
+ aValue >>= aSubTotals;
+ }
+ catch(uno::Exception&)
+ {
+ }
+ }
+
+ return aSubTotals;
+}
+
+void lcl_FilterInclude( std::vector< BOOL >& rResult, std::vector< sal_Int32 >& rSubtotal,
+ const ScDPOutLevelData& rField,
+ const std::vector< ScDPGetPivotDataField >& rFilters,
+ std::vector< BOOL >& rFilterUsed,
+ bool& rBeforeDataLayout,
+ sal_Int32 nGrandTotals, sal_Int32 nDataLayoutIndex,
+ const std::vector<String>& rDataNames, const std::vector<String>& rGivenNames,
+ const ScDPGetPivotDataField& rTarget, const uno::Reference<sheet::XDimensionsSupplier>& xSource )
+{
+ // returns true if a filter was given for the field
+
+ DBG_ASSERT( rFilters.size() == rFilterUsed.size(), "wrong size" );
+
+ const bool bIsDataLayout = ( rField.nDim == nDataLayoutIndex );
+ if (bIsDataLayout)
+ rBeforeDataLayout = false;
+
+ bool bHasFilter = false;
+ ScDPGetPivotDataField aFilter;
+ if ( !bIsDataLayout ) // selection of data field is handled separately
+ {
+ for (SCSIZE nFilterPos = 0; nFilterPos < rFilters.size() && !bHasFilter; ++nFilterPos)
+ {
+ if ( lcl_IsNamedCategoryField( rFilters[nFilterPos], rField ) )
+ {
+ aFilter = rFilters[nFilterPos];
+ rFilterUsed[nFilterPos] = TRUE;
+ bHasFilter = true;
+ }
+ }
+ }
+
+ bool bHasFunc = bHasFilter && aFilter.meFunction != sheet::GeneralFunction_NONE;
+
+ uno::Sequence<sheet::GeneralFunction> aSubTotals;
+ if ( !bIsDataLayout )
+ aSubTotals = lcl_GetSubTotals( xSource, rField );
+ bool bManualSub = ( aSubTotals.getLength() > 0 && aSubTotals[0] != sheet::GeneralFunction_AUTO );
+
+ const uno::Sequence<sheet::MemberResult>& rSequence = rField.aResult;
+ const sheet::MemberResult* pArray = rSequence.getConstArray();
+ sal_Int32 nSize = rSequence.getLength();
+
+ DBG_ASSERT( (sal_Int32)rResult.size() == nSize, "Number of fields do not match result count" );
+
+ sal_Int32 nContCount = 0;
+ sal_Int32 nSubTotalCount = 0;
+ sheet::MemberResult aPrevious;
+ for( sal_Int32 j=0; j < nSize; j++ )
+ {
+ sheet::MemberResult aResultEntry = pArray[j];
+ if ( aResultEntry.Flags & sheet::MemberResultFlags::CONTINUE )
+ {
+ aResultEntry = aPrevious;
+ ++nContCount;
+ }
+ else if ( ( aResultEntry.Flags & sheet::MemberResultFlags::SUBTOTAL ) == 0 )
+ {
+ // count the CONTINUE entries before a SUBTOTAL
+ nContCount = 0;
+ }
+
+ if ( j >= nSize - nGrandTotals )
+ {
+ // mark as subtotal for the preceding data
+ if ( ( aResultEntry.Flags & sheet::MemberResultFlags::SUBTOTAL ) != 0 )
+ {
+ rSubtotal[j] = nSize - nGrandTotals;
+
+ if ( rResult[j] && nGrandTotals > 1 )
+ {
+ // grand total is always automatic
+ sal_Int32 nDataPos = j - ( nSize - nGrandTotals );
+ DBG_ASSERT( nDataPos < (sal_Int32)rDataNames.size(), "wrong data count" );
+ String aSourceName( rDataNames[nDataPos] ); // vector contains source names
+ String aGivenName( rGivenNames[nDataPos] );
+
+ rResult[j] = lcl_IsNamedDataField( rTarget, aSourceName, aGivenName );
+ }
+ }
+
+ // treat "grand total" columns/rows as empty description, as if they were marked
+ // in a previous field
+
+ DBG_ASSERT( ( aResultEntry.Flags &
+ ( sheet::MemberResultFlags::HASMEMBER | sheet::MemberResultFlags::SUBTOTAL ) ) == 0 ||
+ ( aResultEntry.Flags &
+ ( sheet::MemberResultFlags::HASMEMBER | sheet::MemberResultFlags::SUBTOTAL ) ) ==
+ ( sheet::MemberResultFlags::HASMEMBER | sheet::MemberResultFlags::SUBTOTAL ),
+ "non-subtotal member found in grand total result" );
+ aResultEntry.Flags = 0;
+ }
+
+ // mark subtotals (not grand total) for preceding data (assume CONTINUE is set)
+ if ( ( aResultEntry.Flags & sheet::MemberResultFlags::SUBTOTAL ) != 0 )
+ {
+ rSubtotal[j] = nContCount + 1 + nSubTotalCount;
+
+ if ( rResult[j] )
+ {
+ if ( bManualSub )
+ {
+ if ( rBeforeDataLayout )
+ {
+ // manual subtotals and several data fields
+
+ sal_Int32 nDataCount = rDataNames.size();
+ sal_Int32 nFuncPos = nSubTotalCount / nDataCount; // outer order: subtotal functions
+ sal_Int32 nDataPos = nSubTotalCount % nDataCount; // inner order: data fields
+
+ String aSourceName( rDataNames[nDataPos] ); // vector contains source names
+ String aGivenName( rGivenNames[nDataPos] );
+
+ DBG_ASSERT( nFuncPos < aSubTotals.getLength(), "wrong subtotal count" );
+ rResult[j] = lcl_IsNamedDataField( rTarget, aSourceName, aGivenName ) &&
+ aSubTotals[nFuncPos] == aFilter.meFunction;
+ }
+ else
+ {
+ // manual subtotals for a single data field
+
+ DBG_ASSERT( nSubTotalCount < aSubTotals.getLength(), "wrong subtotal count" );
+ rResult[j] = ( aSubTotals[nSubTotalCount] == aFilter.meFunction );
+ }
+ }
+ else // automatic subtotals
+ {
+ if ( rBeforeDataLayout )
+ {
+ DBG_ASSERT( nSubTotalCount < (sal_Int32)rDataNames.size(), "wrong data count" );
+ String aSourceName( rDataNames[nSubTotalCount] ); // vector contains source names
+ String aGivenName( rGivenNames[nSubTotalCount] );
+
+ rResult[j] = lcl_IsNamedDataField( rTarget, aSourceName, aGivenName );
+ }
+
+ // if a function was specified, automatic subtotals never match
+ if ( bHasFunc )
+ rResult[j] = FALSE;
+ }
+ }
+
+ ++nSubTotalCount;
+ }
+ else
+ nSubTotalCount = 0;
+
+ if( rResult[j] )
+ {
+ if ( bIsDataLayout )
+ {
+ if ( ( aResultEntry.Flags & sheet::MemberResultFlags::HASMEMBER ) != 0 )
+ {
+ // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
+ //! preserve original name there?
+ String aSourceName( aResultEntry.Name );
+ aSourceName.EraseTrailingChars( '*' );
+
+ String aGivenName( aResultEntry.Caption ); //! Should use a stored name when available
+ aGivenName.EraseLeadingChars( '\'' );
+
+ rResult[j] = lcl_IsNamedDataField( rTarget, aSourceName, aGivenName );
+ }
+ }
+ else if ( bHasFilter )
+ {
+ // name must match (simple value or subtotal)
+ rResult[j] = ( ( aResultEntry.Flags & sheet::MemberResultFlags::HASMEMBER ) != 0 ) &&
+ lcl_IsCondition( aResultEntry, aFilter );
+
+ // if a function was specified, simple (non-subtotal) values never match
+ if ( bHasFunc && nSubTotalCount == 0 )
+ rResult[j] = FALSE;
+ }
+ // if no condition is given, keep the columns/rows included
+ }
+ aPrevious = aResultEntry;
+ }
+}
+
+void lcl_StripSubTotals( std::vector< BOOL >& rResult, const std::vector< sal_Int32 >& rSubtotal )
+{
+ sal_Int32 nSize = rResult.size();
+ DBG_ASSERT( (sal_Int32)rSubtotal.size() == nSize, "sizes don't match" );
+
+ for (sal_Int32 nPos=0; nPos<nSize; nPos++)
+ if ( rResult[nPos] && rSubtotal[nPos] )
+ {
+ // if a subtotal is included, clear the result flag for the columns/rows that the subtotal includes
+ sal_Int32 nStart = nPos - rSubtotal[nPos];
+ DBG_ASSERT( nStart >= 0, "invalid subtotal count" );
+
+ for (sal_Int32 nPrev = nStart; nPrev < nPos; nPrev++)
+ rResult[nPrev] = FALSE;
+ }
+}
+
+String lcl_GetDataFieldName( const String& rSourceName, sheet::GeneralFunction eFunc )
+{
+ USHORT nStrId = 0;
+ switch ( eFunc )
+ {
+ case sheet::GeneralFunction_SUM: nStrId = STR_FUN_TEXT_SUM; break;
+ case sheet::GeneralFunction_COUNT:
+ case sheet::GeneralFunction_COUNTNUMS: nStrId = STR_FUN_TEXT_COUNT; break;
+ case sheet::GeneralFunction_AVERAGE: nStrId = STR_FUN_TEXT_AVG; break;
+ case sheet::GeneralFunction_MAX: nStrId = STR_FUN_TEXT_MAX; break;
+ case sheet::GeneralFunction_MIN: nStrId = STR_FUN_TEXT_MIN; break;
+ case sheet::GeneralFunction_PRODUCT: nStrId = STR_FUN_TEXT_PRODUCT; break;
+ case sheet::GeneralFunction_STDEV:
+ case sheet::GeneralFunction_STDEVP: nStrId = STR_FUN_TEXT_STDDEV; break;
+ case sheet::GeneralFunction_VAR:
+ case sheet::GeneralFunction_VARP: nStrId = STR_FUN_TEXT_VAR; break;
+ case sheet::GeneralFunction_NONE:
+ case sheet::GeneralFunction_AUTO:
+ default:
+ {
+ DBG_ERRORFILE("wrong function");
+ }
+ }
+ if ( !nStrId )
+ return String();
+
+ String aRet( ScGlobal::GetRscString( nStrId ) );
+ aRet.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " - " ));
+ aRet.Append( rSourceName );
+ return aRet;
+}
+
+// static
+void ScDPOutput::GetDataDimensionNames( String& rSourceName, String& rGivenName,
+ const uno::Reference<uno::XInterface>& xDim )
+{
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ uno::Reference<container::XNamed> xDimName( xDim, uno::UNO_QUERY );
+ if ( xDimProp.is() && xDimName.is() )
+ {
+ // Asterisks are added in ScDPSaveData::WriteToSource to create unique names.
+ //! preserve original name there?
+ rSourceName = xDimName->getName();
+ rSourceName.EraseTrailingChars( '*' );
+
+ // Generate "given name" the same way as in dptabres.
+ //! Should use a stored name when available
+
+ sheet::GeneralFunction eFunc = (sheet::GeneralFunction)ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_FUNCTION),
+ sheet::GeneralFunction_NONE );
+ rGivenName = lcl_GetDataFieldName( rSourceName, eFunc );
+ }
+}
+
+void lcl_GetTableVars( sal_Int32& rGrandTotalCols, sal_Int32& rGrandTotalRows, sal_Int32& rDataLayoutIndex,
+ std::vector<String>& rDataNames, std::vector<String>& rGivenNames,
+ sheet::DataPilotFieldOrientation& rDataOrient,
+ const uno::Reference<sheet::XDimensionsSupplier>& xSource )
+{
+ rDataLayoutIndex = -1; // invalid
+ rGrandTotalCols = 0;
+ rGrandTotalRows = 0;
+ rDataOrient = sheet::DataPilotFieldOrientation_HIDDEN;
+
+ uno::Reference<beans::XPropertySet> xSrcProp( xSource, uno::UNO_QUERY );
+ BOOL bColGrand = ScUnoHelpFunctions::GetBoolProperty( xSrcProp,
+ rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND) );
+ if ( bColGrand )
+ rGrandTotalCols = 1; // default if data layout not in columns
+
+ BOOL bRowGrand = ScUnoHelpFunctions::GetBoolProperty( xSrcProp,
+ rtl::OUString::createFromAscii(DP_PROP_ROWGRAND) );
+ if ( bRowGrand )
+ rGrandTotalRows = 1; // default if data layout not in rows
+
+ if ( xSource.is() )
+ {
+ // find index and orientation of "data layout" dimension, count data dimensions
+
+ sal_Int32 nDataCount = 0;
+
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess( xSource->getDimensions() );
+ long nDimCount = xDims->getCount();
+ for (long nDim=0; nDim<nDimCount; nDim++)
+ {
+ uno::Reference<uno::XInterface> xDim =
+ ScUnoHelpFunctions::AnyToInterface( xDims->getByIndex(nDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ if ( xDimProp.is() )
+ {
+ sheet::DataPilotFieldOrientation eDimOrient =
+ (sheet::DataPilotFieldOrientation) ScUnoHelpFunctions::GetEnumProperty(
+ xDimProp, rtl::OUString::createFromAscii(DP_PROP_ORIENTATION),
+ sheet::DataPilotFieldOrientation_HIDDEN );
+ if ( ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) ) )
+ {
+ rDataLayoutIndex = nDim;
+ rDataOrient = eDimOrient;
+ }
+ if ( eDimOrient == sheet::DataPilotFieldOrientation_DATA )
+ {
+ String aSourceName;
+ String aGivenName;
+ ScDPOutput::GetDataDimensionNames( aSourceName, aGivenName, xDim );
+ rDataNames.push_back( aSourceName );
+ rGivenNames.push_back( aGivenName );
+
+ ++nDataCount;
+ }
+ }
+ }
+
+ if ( ( rDataOrient == sheet::DataPilotFieldOrientation_COLUMN ) && bColGrand )
+ rGrandTotalCols = nDataCount;
+ else if ( ( rDataOrient == sheet::DataPilotFieldOrientation_ROW ) && bRowGrand )
+ rGrandTotalRows = nDataCount;
+ }
+}
+
+// Returns TRUE on success and stores the result in rTarget
+// Returns FALSE if rFilters or rTarget describes something that is not visible
+BOOL ScDPOutput::GetPivotData( ScDPGetPivotDataField& rTarget,
+ const std::vector< ScDPGetPivotDataField >& rFilters )
+{
+ CalcSizes();
+
+ // need to know about grand total columns/rows:
+ sal_Int32 nGrandTotalCols;
+ sal_Int32 nGrandTotalRows;
+ sal_Int32 nDataLayoutIndex;
+ std::vector<String> aDataNames;
+ std::vector<String> aGivenNames;
+ sheet::DataPilotFieldOrientation eDataOrient;
+ lcl_GetTableVars( nGrandTotalCols, nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, eDataOrient, xSource );
+
+ if ( aDataNames.empty() )
+ return FALSE; // incomplete table without data fields -> no result
+
+ if ( eDataOrient == sheet::DataPilotFieldOrientation_HIDDEN )
+ {
+ // no data layout field -> single data field -> must match the selected field in rTarget
+
+ DBG_ASSERT( aDataNames.size() == 1, "several data fields but no data layout field" );
+ if ( !lcl_IsNamedDataField( rTarget, aDataNames[0], aGivenNames[0] ) )
+ return FALSE;
+ }
+
+ std::vector< BOOL > aIncludeCol( nColCount, TRUE );
+ std::vector< sal_Int32 > aSubtotalCol( nColCount, 0 );
+ std::vector< BOOL > aIncludeRow( nRowCount, TRUE );
+ std::vector< sal_Int32 > aSubtotalRow( nRowCount, 0 );
+
+ std::vector< BOOL > aFilterUsed( rFilters.size(), FALSE );
+
+ long nField;
+ long nCol;
+ long nRow;
+ bool bBeforeDataLayout;
+
+ // look in column fields
+
+ bBeforeDataLayout = ( eDataOrient == sheet::DataPilotFieldOrientation_COLUMN );
+ for (nField=0; nField<nColFieldCount; nField++)
+ lcl_FilterInclude( aIncludeCol, aSubtotalCol, pColFields[nField], rFilters, aFilterUsed, bBeforeDataLayout,
+ nGrandTotalCols, nDataLayoutIndex, aDataNames, aGivenNames, rTarget, xSource );
+
+ // look in row fields
+
+ bBeforeDataLayout = ( eDataOrient == sheet::DataPilotFieldOrientation_ROW );
+ for (nField=0; nField<nRowFieldCount; nField++)
+ lcl_FilterInclude( aIncludeRow, aSubtotalRow, pRowFields[nField], rFilters, aFilterUsed, bBeforeDataLayout,
+ nGrandTotalRows, nDataLayoutIndex, aDataNames, aGivenNames, rTarget, xSource );
+
+ // page fields
+
+ for (nField=0; nField<nPageFieldCount; nField++)
+ if ( !lcl_CheckPageField( pPageFields[nField], rFilters, aFilterUsed ) )
+ return FALSE;
+
+ // all filter fields must be used
+ for (SCSIZE nFilter=0; nFilter<aFilterUsed.size(); nFilter++)
+ if (!aFilterUsed[nFilter])
+ return FALSE;
+
+ lcl_StripSubTotals( aIncludeCol, aSubtotalCol );
+ lcl_StripSubTotals( aIncludeRow, aSubtotalRow );
+
+ long nColPos = 0;
+ long nColIncluded = 0;
+ for (nCol=0; nCol<nColCount; nCol++)
+ if (aIncludeCol[nCol])
+ {
+ nColPos = nCol;
+ ++nColIncluded;
+ }
+
+ long nRowPos = 0;
+ long nRowIncluded = 0;
+ for (nRow=0; nRow<nRowCount; nRow++)
+ if (aIncludeRow[nRow])
+ {
+ nRowPos = nRow;
+ ++nRowIncluded;
+ }
+
+ if ( nColIncluded != 1 || nRowIncluded != 1 )
+ return FALSE;
+
+ const uno::Sequence<sheet::DataResult>& rDataRow = aData[nRowPos];
+ if ( nColPos >= rDataRow.getLength() )
+ return FALSE;
+
+ const sheet::DataResult& rResult = rDataRow[nColPos];
+ if ( rResult.Flags & sheet::DataResultFlags::ERROR )
+ return FALSE; //! different error?
+
+ rTarget.mbValIsStr = FALSE;
+ rTarget.mnValNum = rResult.Value;
+
+ return TRUE;
+}
+
+BOOL ScDPOutput::IsFilterButton( const ScAddress& rPos )
+{
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+ if ( nTab != aStartPos.Tab() || !bDoFilter )
+ return FALSE; // wrong sheet or no button at all
+
+ // filter button is at top left
+ return ( nCol == aStartPos.Col() && nRow == aStartPos.Row() );
+}
+
+long ScDPOutput::GetHeaderDim( const ScAddress& rPos, USHORT& rOrient )
+{
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+ if ( nTab != aStartPos.Tab() )
+ return -1; // wrong sheet
+
+ // calculate output positions and sizes
+
+ CalcSizes();
+
+ // test for column header
+
+ if ( nRow == nTabStartRow && nCol >= nDataStartCol && nCol < nDataStartCol + nColFieldCount )
+ {
+ rOrient = sheet::DataPilotFieldOrientation_COLUMN;
+ long nField = nCol - nDataStartCol;
+ return pColFields[nField].nDim;
+ }
+
+ // test for row header
+
+ if ( nRow+1 == nDataStartRow && nCol >= nTabStartCol && nCol < nTabStartCol + nRowFieldCount )
+ {
+ rOrient = sheet::DataPilotFieldOrientation_ROW;
+ long nField = nCol - nTabStartCol;
+ return pRowFields[nField].nDim;
+ }
+
+ // test for page field
+
+ SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
+ if ( nCol == aStartPos.Col() && nRow >= nPageStartRow && nRow < nPageStartRow + nPageFieldCount )
+ {
+ rOrient = sheet::DataPilotFieldOrientation_PAGE;
+ long nField = nRow - nPageStartRow;
+ return pPageFields[nField].nDim;
+ }
+
+ //! single data field (?)
+
+ rOrient = sheet::DataPilotFieldOrientation_HIDDEN;
+ return -1; // invalid
+}
+
+BOOL ScDPOutput::GetHeaderDrag( const ScAddress& rPos, BOOL bMouseLeft, BOOL bMouseTop,
+ long nDragDim,
+ Rectangle& rPosRect, USHORT& rOrient, long& rDimPos )
+{
+ // Rectangle instead of ScRange for rPosRect to allow for negative values
+
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+ if ( nTab != aStartPos.Tab() )
+ return FALSE; // wrong sheet
+
+ // calculate output positions and sizes
+
+ CalcSizes();
+
+ // test for column header
+
+ if ( nCol >= nDataStartCol && nCol <= nTabEndCol &&
+ nRow + 1 >= nMemberStartRow && nRow < nMemberStartRow + nColFieldCount )
+ {
+ long nField = nRow - nMemberStartRow;
+ if (nField < 0)
+ {
+ nField = 0;
+ bMouseTop = TRUE;
+ }
+ //! find start of dimension
+
+ rPosRect = Rectangle( nDataStartCol, nMemberStartRow + nField,
+ nTabEndCol, nMemberStartRow + nField -1 );
+
+ BOOL bFound = FALSE; // is this within the same orientation?
+ BOOL bBeforeDrag = FALSE;
+ BOOL bAfterDrag = FALSE;
+ for (long nPos=0; nPos<nColFieldCount && !bFound; nPos++)
+ {
+ if (pColFields[nPos].nDim == nDragDim)
+ {
+ bFound = TRUE;
+ if ( nField < nPos )
+ bBeforeDrag = TRUE;
+ else if ( nField > nPos )
+ bAfterDrag = TRUE;
+ }
+ }
+
+ if ( bFound )
+ {
+ if (!bBeforeDrag)
+ {
+ ++rPosRect.Bottom();
+ if (bAfterDrag)
+ ++rPosRect.Top();
+ }
+ }
+ else
+ {
+ if ( !bMouseTop )
+ {
+ ++rPosRect.Top();
+ ++rPosRect.Bottom();
+ ++nField;
+ }
+ }
+
+ rOrient = sheet::DataPilotFieldOrientation_COLUMN;
+ rDimPos = nField; //!...
+ return TRUE;
+ }
+
+ // test for row header
+
+ // special case if no row fields
+ BOOL bSpecial = ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow &&
+ nRowFieldCount == 0 && nCol == nTabStartCol && bMouseLeft );
+
+ if ( bSpecial || ( nRow+1 >= nDataStartRow && nRow <= nTabEndRow &&
+ nCol + 1 >= nTabStartCol && nCol < nTabStartCol + nRowFieldCount ) )
+ {
+ long nField = nCol - nTabStartCol;
+ //! find start of dimension
+
+ rPosRect = Rectangle( nTabStartCol + nField, nDataStartRow - 1,
+ nTabStartCol + nField - 1, nTabEndRow );
+
+ BOOL bFound = FALSE; // is this within the same orientation?
+ BOOL bBeforeDrag = FALSE;
+ BOOL bAfterDrag = FALSE;
+ for (long nPos=0; nPos<nRowFieldCount && !bFound; nPos++)
+ {
+ if (pRowFields[nPos].nDim == nDragDim)
+ {
+ bFound = TRUE;
+ if ( nField < nPos )
+ bBeforeDrag = TRUE;
+ else if ( nField > nPos )
+ bAfterDrag = TRUE;
+ }
+ }
+
+ if ( bFound )
+ {
+ if (!bBeforeDrag)
+ {
+ ++rPosRect.Right();
+ if (bAfterDrag)
+ ++rPosRect.Left();
+ }
+ }
+ else
+ {
+ if ( !bMouseLeft )
+ {
+ ++rPosRect.Left();
+ ++rPosRect.Right();
+ ++nField;
+ }
+ }
+
+ rOrient = sheet::DataPilotFieldOrientation_ROW;
+ rDimPos = nField; //!...
+ return TRUE;
+ }
+
+ // test for page fields
+
+ SCROW nPageStartRow = aStartPos.Row() + ( bDoFilter ? 1 : 0 );
+ if ( nCol >= aStartPos.Col() && nCol <= nTabEndCol &&
+ nRow + 1 >= nPageStartRow && nRow < nPageStartRow + nPageFieldCount )
+ {
+ long nField = nRow - nPageStartRow;
+ if (nField < 0)
+ {
+ nField = 0;
+ bMouseTop = TRUE;
+ }
+ //! find start of dimension
+
+ rPosRect = Rectangle( aStartPos.Col(), nPageStartRow + nField,
+ nTabEndCol, nPageStartRow + nField - 1 );
+
+ BOOL bFound = FALSE; // is this within the same orientation?
+ BOOL bBeforeDrag = FALSE;
+ BOOL bAfterDrag = FALSE;
+ for (long nPos=0; nPos<nPageFieldCount && !bFound; nPos++)
+ {
+ if (pPageFields[nPos].nDim == nDragDim)
+ {
+ bFound = TRUE;
+ if ( nField < nPos )
+ bBeforeDrag = TRUE;
+ else if ( nField > nPos )
+ bAfterDrag = TRUE;
+ }
+ }
+
+ if ( bFound )
+ {
+ if (!bBeforeDrag)
+ {
+ ++rPosRect.Bottom();
+ if (bAfterDrag)
+ ++rPosRect.Top();
+ }
+ }
+ else
+ {
+ if ( !bMouseTop )
+ {
+ ++rPosRect.Top();
+ ++rPosRect.Bottom();
+ ++nField;
+ }
+ }
+
+ rOrient = sheet::DataPilotFieldOrientation_PAGE;
+ rDimPos = nField; //!...
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
diff --git a/sc/source/core/data/dpsave.cxx b/sc/source/core/data/dpsave.cxx
new file mode 100644
index 000000000000..f4180312ce0d
--- /dev/null
+++ b/sc/source/core/data/dpsave.cxx
@@ -0,0 +1,1127 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dpsave.cxx,v $
+ * $Revision: 1.13.32.3 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "dpsave.hxx"
+#include "dpdimsave.hxx"
+#include "miscuno.hxx"
+#include "scerrors.hxx"
+#include "unonames.hxx"
+#include "global.hxx"
+
+#include <tools/debug.hxx>
+
+#include <com/sun/star/sheet/GeneralFunction.hpp>
+#include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldLayoutInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReference.hpp>
+#include <com/sun/star/sheet/DataPilotFieldSortInfo.hpp>
+#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
+#include <com/sun/star/sheet/TableFilterField.hpp>
+#include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
+#include <com/sun/star/sheet/XLevelsSupplier.hpp>
+#include <com/sun/star/sheet/XMembersSupplier.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/util/XCloneable.hpp>
+
+using namespace com::sun::star;
+
+// -----------------------------------------------------------------------
+
+#define SC_DPSAVEMODE_NO 0
+#define SC_DPSAVEMODE_YES 1
+#define SC_DPSAVEMODE_DONTKNOW 2
+
+// -----------------------------------------------------------------------
+
+//! move to a header file
+//! use names from unonames.hxx?
+#define DP_PROP_COLUMNGRAND "ColumnGrand"
+#define DP_PROP_FUNCTION "Function"
+#define DP_PROP_IGNOREEMPTY "IgnoreEmptyRows"
+#define DP_PROP_ISDATALAYOUT "IsDataLayoutDimension"
+#define DP_PROP_ISVISIBLE "IsVisible"
+#define DP_PROP_ORIENTATION "Orientation"
+#define DP_PROP_REPEATIFEMPTY "RepeatIfEmpty"
+#define DP_PROP_ROWGRAND "RowGrand"
+#define DP_PROP_SHOWDETAILS "ShowDetails"
+#define DP_PROP_SHOWEMPTY "ShowEmpty"
+#define DP_PROP_SUBTOTALS "SubTotals"
+#define DP_PROP_USEDHIERARCHY "UsedHierarchy"
+#define DP_PROP_FILTER "Filter"
+#define DP_PROP_POSITION "Position"
+
+// -----------------------------------------------------------------------
+
+void lcl_SetBoolProperty( const uno::Reference<beans::XPropertySet>& xProp,
+ const rtl::OUString& rName, sal_Bool bValue )
+{
+ //! move to ScUnoHelpFunctions?
+
+ xProp->setPropertyValue( rName, uno::Any( &bValue, getBooleanCppuType() ) );
+}
+
+// -----------------------------------------------------------------------
+
+void lcl_SkipExtra( SvStream& rStream )
+{
+ USHORT nExtra;
+ rStream >> nExtra;
+ if ( nExtra )
+ {
+ rStream.SeekRel( nExtra );
+ if ( rStream.GetError() == SVSTREAM_OK )
+ rStream.SetError( SCWARN_IMPORT_INFOLOST );
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ScDPSaveMember::ScDPSaveMember(const String& rName) :
+ aName( rName ),
+ nVisibleMode( SC_DPSAVEMODE_DONTKNOW ),
+ nShowDetailsMode( SC_DPSAVEMODE_DONTKNOW )
+{
+}
+
+ScDPSaveMember::ScDPSaveMember(const ScDPSaveMember& r) :
+ aName( r.aName ),
+ nVisibleMode( r.nVisibleMode ),
+ nShowDetailsMode( r.nShowDetailsMode )
+{
+}
+
+ScDPSaveMember::~ScDPSaveMember()
+{
+}
+
+BOOL ScDPSaveMember::operator== ( const ScDPSaveMember& r ) const
+{
+ if ( aName != r.aName ||
+ nVisibleMode != r.nVisibleMode ||
+ nShowDetailsMode != r.nShowDetailsMode )
+ return FALSE;
+
+ return TRUE;
+}
+
+BOOL ScDPSaveMember::HasIsVisible() const
+{
+ return nVisibleMode != SC_DPSAVEMODE_DONTKNOW;
+}
+
+void ScDPSaveMember::SetIsVisible(BOOL bSet)
+{
+ nVisibleMode = bSet;
+}
+
+BOOL ScDPSaveMember::HasShowDetails() const
+{
+ return nShowDetailsMode != SC_DPSAVEMODE_DONTKNOW;
+}
+
+void ScDPSaveMember::SetShowDetails(BOOL bSet)
+{
+ nShowDetailsMode = bSet;
+}
+
+void ScDPSaveMember::SetName( const String& rNew )
+{
+ // Used only if the source member was renamed (groups).
+ // For UI renaming of members, a layout name must be used.
+
+ aName = rNew;
+}
+
+void ScDPSaveMember::WriteToSource( const uno::Reference<uno::XInterface>& xMember, sal_Int32 nPosition )
+{
+ // nothing to do?
+ if ( nVisibleMode == SC_DPSAVEMODE_DONTKNOW && nShowDetailsMode == SC_DPSAVEMODE_DONTKNOW && nPosition < 0 )
+ return;
+
+ uno::Reference<beans::XPropertySet> xMembProp( xMember, uno::UNO_QUERY );
+ DBG_ASSERT( xMembProp.is(), "no properties at member" );
+ if ( xMembProp.is() )
+ {
+ // exceptions are caught at ScDPSaveData::WriteToSource
+
+ if ( nVisibleMode != SC_DPSAVEMODE_DONTKNOW )
+ lcl_SetBoolProperty( xMembProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISVISIBLE), (BOOL)nVisibleMode );
+
+ if ( nShowDetailsMode != SC_DPSAVEMODE_DONTKNOW )
+ lcl_SetBoolProperty( xMembProp,
+ rtl::OUString::createFromAscii(DP_PROP_SHOWDETAILS), (BOOL)nShowDetailsMode );
+
+ if ( nPosition >= 0 )
+ {
+ try
+ {
+ xMembProp->setPropertyValue( rtl::OUString::createFromAscii(DP_PROP_POSITION), uno::Any(nPosition) );
+ }
+ catch ( uno::Exception& )
+ {
+ // position is optional - exception must be ignored
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ScDPSaveDimension::ScDPSaveDimension(const String& rName, BOOL bDataLayout) :
+ aName( rName ),
+ pLayoutName( NULL ),
+ pSelectedPage( NULL ),
+ bIsDataLayout( bDataLayout ),
+ bDupFlag( FALSE ),
+ nOrientation( sheet::DataPilotFieldOrientation_HIDDEN ),
+ nFunction( sheet::GeneralFunction_AUTO ),
+ nUsedHierarchy( -1 ),
+ nShowEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
+ bSubTotalDefault( TRUE ),
+ nSubTotalCount( 0 ),
+ pSubTotalFuncs( NULL ),
+ pReferenceValue( NULL ),
+ pSortInfo( NULL ),
+ pAutoShowInfo( NULL ),
+ pLayoutInfo( NULL )
+{
+}
+
+ScDPSaveDimension::ScDPSaveDimension(const ScDPSaveDimension& r) :
+ aName( r.aName ),
+ bIsDataLayout( r.bIsDataLayout ),
+ bDupFlag( r.bDupFlag ),
+ nOrientation( r.nOrientation ),
+ nFunction( r.nFunction ),
+ nUsedHierarchy( r.nUsedHierarchy ),
+ nShowEmptyMode( r.nShowEmptyMode ),
+ bSubTotalDefault( r.bSubTotalDefault ),
+ nSubTotalCount( r.nSubTotalCount ),
+ pSubTotalFuncs( NULL )
+{
+ if ( nSubTotalCount && r.pSubTotalFuncs )
+ {
+ pSubTotalFuncs = new USHORT[nSubTotalCount];
+ for (long nSub=0; nSub<nSubTotalCount; nSub++)
+ pSubTotalFuncs[nSub] = r.pSubTotalFuncs[nSub];
+ }
+
+ for (MemberList::const_iterator i=r.maMemberList.begin(); i != r.maMemberList.end() ; i++)
+ {
+ const String& rName = (*i)->GetName();
+ ScDPSaveMember* pNew = new ScDPSaveMember( **i );
+ maMemberHash[rName] = pNew;
+ maMemberList.push_back( pNew );
+ }
+ if (r.pReferenceValue)
+ pReferenceValue = new sheet::DataPilotFieldReference( *(r.pReferenceValue) );
+ else
+ pReferenceValue = NULL;
+ if (r.pSortInfo)
+ pSortInfo = new sheet::DataPilotFieldSortInfo( *(r.pSortInfo) );
+ else
+ pSortInfo = NULL;
+ if (r.pAutoShowInfo)
+ pAutoShowInfo = new sheet::DataPilotFieldAutoShowInfo( *(r.pAutoShowInfo) );
+ else
+ pAutoShowInfo = NULL;
+ if (r.pLayoutInfo)
+ pLayoutInfo = new sheet::DataPilotFieldLayoutInfo( *(r.pLayoutInfo) );
+ else
+ pLayoutInfo = NULL;
+ if (r.pLayoutName)
+ pLayoutName = new String( *(r.pLayoutName) );
+ else
+ pLayoutName = NULL;
+ if (r.pSelectedPage)
+ pSelectedPage = new String( *(r.pSelectedPage) );
+ else
+ pSelectedPage = NULL;
+}
+
+ScDPSaveDimension::~ScDPSaveDimension()
+{
+ for (MemberHash::const_iterator i=maMemberHash.begin(); i != maMemberHash.end() ; i++)
+ delete i->second;
+ delete pReferenceValue;
+ delete pSortInfo;
+ delete pAutoShowInfo;
+ delete pLayoutInfo;
+ delete pLayoutName;
+ delete pSelectedPage;
+ delete [] pSubTotalFuncs;
+}
+
+BOOL ScDPSaveDimension::operator== ( const ScDPSaveDimension& r ) const
+{
+ if ( aName != r.aName ||
+ bIsDataLayout != r.bIsDataLayout ||
+ bDupFlag != r.bDupFlag ||
+ nOrientation != r.nOrientation ||
+ nFunction != r.nFunction ||
+ nUsedHierarchy != r.nUsedHierarchy ||
+ nShowEmptyMode != r.nShowEmptyMode ||
+ bSubTotalDefault != r.bSubTotalDefault ||
+ nSubTotalCount != r.nSubTotalCount )
+ return FALSE;
+
+ if ( nSubTotalCount && ( !pSubTotalFuncs || !r.pSubTotalFuncs ) ) // should not happen
+ return FALSE;
+
+ long i;
+ for (i=0; i<nSubTotalCount; i++)
+ if ( pSubTotalFuncs[i] != r.pSubTotalFuncs[i] )
+ return FALSE;
+
+ if (maMemberHash.size() != r.maMemberHash.size() )
+ return FALSE;
+
+ MemberList::const_iterator a=maMemberList.begin();
+ MemberList::const_iterator b=r.maMemberList.begin();
+ for (; a != maMemberList.end() ; ++a, ++b)
+ if (!(**a == **b))
+ return FALSE;
+
+ return TRUE;
+}
+
+void ScDPSaveDimension::AddMember(ScDPSaveMember* pMember)
+{
+ const String & rName = pMember->GetName();
+ MemberHash::iterator aExisting = maMemberHash.find( rName );
+ if ( aExisting == maMemberHash.end() )
+ {
+ std::pair< const String, ScDPSaveMember *> key( rName, pMember );
+ maMemberHash.insert ( key );
+ }
+ else
+ {
+ maMemberList.remove( aExisting->second );
+ delete aExisting->second;
+ aExisting->second = pMember;
+ }
+ maMemberList.push_back( pMember );
+}
+
+void ScDPSaveDimension::SetName( const String& rNew )
+{
+ // Used only if the source dim was renamed (groups).
+ // For UI renaming of dimensions, the layout name must be used.
+
+ aName = rNew;
+}
+
+void ScDPSaveDimension::SetOrientation(USHORT nNew)
+{
+ nOrientation = nNew;
+}
+
+void ScDPSaveDimension::SetSubTotals(BOOL bSet)
+{
+ if (bSet)
+ {
+ USHORT nFunc = sheet::GeneralFunction_AUTO;
+ SetSubTotals( 1, &nFunc );
+ }
+ else
+ SetSubTotals( 0, NULL );
+}
+
+void ScDPSaveDimension::SetSubTotals(long nCount, const USHORT* pFuncs)
+{
+ if (pSubTotalFuncs)
+ delete [] pSubTotalFuncs;
+ nSubTotalCount = nCount;
+ if ( nCount && pFuncs )
+ {
+ pSubTotalFuncs = new USHORT[nCount];
+ for (long i=0; i<nCount; i++)
+ pSubTotalFuncs[i] = pFuncs[i];
+ }
+ else
+ pSubTotalFuncs = NULL;
+
+ bSubTotalDefault = FALSE;
+}
+
+void ScDPSaveDimension::SetShowEmpty(BOOL bSet)
+{
+ nShowEmptyMode = bSet;
+}
+
+void ScDPSaveDimension::SetFunction(USHORT nNew)
+{
+ nFunction = nNew;
+}
+
+void ScDPSaveDimension::SetUsedHierarchy(long nNew)
+{
+ nUsedHierarchy = nNew;
+}
+
+BOOL ScDPSaveDimension::HasLayoutName() const
+{
+ return ( pLayoutName != NULL );
+}
+
+void ScDPSaveDimension::SetLayoutName(const String* pName)
+{
+ delete pLayoutName;
+ if (pName)
+ pLayoutName = new String( *pName );
+ else
+ pLayoutName = NULL;
+}
+
+const String& ScDPSaveDimension::GetLayoutName() const
+{
+ if (pLayoutName)
+ return *pLayoutName;
+ return aName;
+}
+
+void ScDPSaveDimension::SetReferenceValue(const sheet::DataPilotFieldReference* pNew)
+{
+ delete pReferenceValue;
+ if (pNew)
+ pReferenceValue = new sheet::DataPilotFieldReference(*pNew);
+ else
+ pReferenceValue = NULL;
+}
+
+void ScDPSaveDimension::SetSortInfo(const sheet::DataPilotFieldSortInfo* pNew)
+{
+ delete pSortInfo;
+ if (pNew)
+ pSortInfo = new sheet::DataPilotFieldSortInfo(*pNew);
+ else
+ pSortInfo = NULL;
+}
+
+void ScDPSaveDimension::SetAutoShowInfo(const sheet::DataPilotFieldAutoShowInfo* pNew)
+{
+ delete pAutoShowInfo;
+ if (pNew)
+ pAutoShowInfo = new sheet::DataPilotFieldAutoShowInfo(*pNew);
+ else
+ pAutoShowInfo = NULL;
+}
+
+void ScDPSaveDimension::SetLayoutInfo(const sheet::DataPilotFieldLayoutInfo* pNew)
+{
+ delete pLayoutInfo;
+ if (pNew)
+ pLayoutInfo = new sheet::DataPilotFieldLayoutInfo(*pNew);
+ else
+ pLayoutInfo = NULL;
+}
+
+void ScDPSaveDimension::SetCurrentPage( const String* pPage )
+{
+ delete pSelectedPage;
+ if (pPage)
+ pSelectedPage = new String( *pPage );
+ else
+ pSelectedPage = NULL;
+}
+
+BOOL ScDPSaveDimension::HasCurrentPage() const
+{
+ return ( pSelectedPage != NULL );
+}
+
+const String& ScDPSaveDimension::GetCurrentPage() const
+{
+ if (pSelectedPage)
+ return *pSelectedPage;
+ return EMPTY_STRING;
+}
+
+ScDPSaveMember* ScDPSaveDimension::GetExistingMemberByName(const String& rName)
+{
+ MemberHash::const_iterator res = maMemberHash.find (rName);
+ if (res != maMemberHash.end())
+ return res->second;
+ return NULL;
+}
+
+
+ScDPSaveMember* ScDPSaveDimension::GetMemberByName(const String& rName)
+{
+ MemberHash::const_iterator res = maMemberHash.find (rName);
+ if (res != maMemberHash.end())
+ return res->second;
+
+ ScDPSaveMember* pNew = new ScDPSaveMember( rName );
+ maMemberHash[rName] = pNew;
+ maMemberList.push_back( pNew );
+ return pNew;
+}
+
+void ScDPSaveDimension::SetMemberPosition( const String& rName, sal_Int32 nNewPos )
+{
+ ScDPSaveMember* pMember = GetMemberByName( rName ); // make sure it exists and is in the hash
+
+ maMemberList.remove( pMember );
+
+ MemberList::iterator aIter = maMemberList.begin();
+ for (sal_Int32 i=0; i<nNewPos && aIter != maMemberList.end(); i++)
+ ++aIter;
+ maMemberList.insert( aIter, pMember );
+}
+
+void ScDPSaveDimension::WriteToSource( const uno::Reference<uno::XInterface>& xDim )
+{
+ uno::Reference<beans::XPropertySet> xDimProp( xDim, uno::UNO_QUERY );
+ DBG_ASSERT( xDimProp.is(), "no properties at dimension" );
+ if ( xDimProp.is() )
+ {
+ // exceptions are caught at ScDPSaveData::WriteToSource
+ uno::Any aAny;
+
+ sheet::DataPilotFieldOrientation eOrient = (sheet::DataPilotFieldOrientation)nOrientation;
+ aAny <<= eOrient;
+ xDimProp->setPropertyValue( rtl::OUString::createFromAscii(DP_PROP_ORIENTATION), aAny );
+
+ sheet::GeneralFunction eFunc = (sheet::GeneralFunction)nFunction;
+ aAny <<= eFunc;
+ xDimProp->setPropertyValue( rtl::OUString::createFromAscii(DP_PROP_FUNCTION), aAny );
+
+ if ( nUsedHierarchy >= 0 )
+ {
+ aAny <<= (INT32)nUsedHierarchy;
+ xDimProp->setPropertyValue( rtl::OUString::createFromAscii(DP_PROP_USEDHIERARCHY), aAny );
+ }
+
+ if ( pReferenceValue )
+ {
+ aAny <<= *pReferenceValue;
+ xDimProp->setPropertyValue( rtl::OUString::createFromAscii(SC_UNO_REFVALUE), aAny );
+ }
+
+ uno::Sequence<sheet::TableFilterField> aFilter;
+ // set the selected page field only if the dimension is used as page dimension
+ if ( pSelectedPage && nOrientation == sheet::DataPilotFieldOrientation_PAGE )
+ {
+ // single filter field: first field equal to selected string
+ sheet::TableFilterField aField( sheet::FilterConnection_AND, 0,
+ sheet::FilterOperator_EQUAL, sal_False, 0.0, *pSelectedPage );
+ aFilter = uno::Sequence<sheet::TableFilterField>( &aField, 1 );
+ }
+ // else keep empty sequence
+ try
+ {
+ aAny <<= aFilter;
+ xDimProp->setPropertyValue( rtl::OUString::createFromAscii(DP_PROP_FILTER), aAny );
+ }
+ catch ( beans::UnknownPropertyException& )
+ {
+ // recent addition - allow source to not handle it (no error)
+ }
+ }
+
+ // Level loop outside of maMemberList loop
+ // because SubTotals have to be set independently of known members
+
+ long nCount = maMemberHash.size();
+
+ long nHierCount = 0;
+ uno::Reference<container::XIndexAccess> xHiers;
+ uno::Reference<sheet::XHierarchiesSupplier> xHierSupp( xDim, uno::UNO_QUERY );
+ if ( xHierSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xHiersName = xHierSupp->getHierarchies();
+ xHiers = new ScNameToIndexAccess( xHiersName );
+ nHierCount = xHiers->getCount();
+ }
+
+ for (long nHier=0; nHier<nHierCount; nHier++)
+ {
+ uno::Reference<uno::XInterface> xHierarchy = ScUnoHelpFunctions::AnyToInterface( xHiers->getByIndex(nHier) );
+
+ long nLevCount = 0;
+ uno::Reference<container::XIndexAccess> xLevels;
+ uno::Reference<sheet::XLevelsSupplier> xLevSupp( xHierarchy, uno::UNO_QUERY );
+ if ( xLevSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xLevelsName = xLevSupp->getLevels();
+ xLevels = new ScNameToIndexAccess( xLevelsName );
+ nLevCount = xLevels->getCount();
+ }
+
+ for (long nLev=0; nLev<nLevCount; nLev++)
+ {
+ uno::Reference<uno::XInterface> xLevel = ScUnoHelpFunctions::AnyToInterface( xLevels->getByIndex(nLev) );
+ uno::Reference<beans::XPropertySet> xLevProp( xLevel, uno::UNO_QUERY );
+ DBG_ASSERT( xLevProp.is(), "no properties at level" );
+ if ( xLevProp.is() )
+ {
+ uno::Any aAny;
+ if ( !bSubTotalDefault )
+ {
+ if ( !pSubTotalFuncs )
+ nSubTotalCount = 0;
+
+ uno::Sequence<sheet::GeneralFunction> aSeq(nSubTotalCount);
+ sheet::GeneralFunction* pArray = aSeq.getArray();
+ for (long i=0; i<nSubTotalCount; i++)
+ pArray[i] = (sheet::GeneralFunction)pSubTotalFuncs[i];
+ aAny <<= aSeq;
+ xLevProp->setPropertyValue( rtl::OUString::createFromAscii(DP_PROP_SUBTOTALS), aAny );
+ }
+ if ( nShowEmptyMode != SC_DPSAVEMODE_DONTKNOW )
+ lcl_SetBoolProperty( xLevProp,
+ rtl::OUString::createFromAscii(DP_PROP_SHOWEMPTY), (BOOL)nShowEmptyMode );
+
+ if ( pSortInfo )
+ {
+ aAny <<= *pSortInfo;
+ try
+ {
+ xLevProp->setPropertyValue( rtl::OUString::createFromAscii(SC_UNO_SORTING), aAny );
+ }
+ catch ( beans::UnknownPropertyException& )
+ {
+ // recent addition - allow source to not handle it (no error)
+ }
+ }
+ if ( pAutoShowInfo )
+ {
+ aAny <<= *pAutoShowInfo;
+ try
+ {
+ xLevProp->setPropertyValue( rtl::OUString::createFromAscii(SC_UNO_AUTOSHOW), aAny );
+ }
+ catch ( beans::UnknownPropertyException& )
+ {
+ // recent addition - allow source to not handle it (no error)
+ }
+ }
+ if ( pLayoutInfo )
+ {
+ aAny <<= *pLayoutInfo;
+ try
+ {
+ xLevProp->setPropertyValue( rtl::OUString::createFromAscii(SC_UNO_LAYOUT), aAny );
+ }
+ catch ( beans::UnknownPropertyException& )
+ {
+ // recent addition - allow source to not handle it (no error)
+ }
+ }
+
+ // exceptions are caught at ScDPSaveData::WriteToSource
+ }
+
+ if ( nCount > 0 )
+ {
+ uno::Reference<sheet::XMembersSupplier> xMembSupp( xLevel, uno::UNO_QUERY );
+ if ( xMembSupp.is() )
+ {
+ uno::Reference<container::XNameAccess> xMembers = xMembSupp->getMembers();
+ if ( xMembers.is() )
+ {
+ sal_Int32 nPosition = -1; // set position only in manual mode
+ if ( !pSortInfo || pSortInfo->Mode == sheet::DataPilotFieldSortMode::MANUAL )
+ nPosition = 0;
+
+ for (MemberList::const_iterator i=maMemberList.begin(); i != maMemberList.end() ; i++)
+ {
+ rtl::OUString aMemberName = (*i)->GetName();
+ if ( xMembers->hasByName( aMemberName ) )
+ {
+ uno::Reference<uno::XInterface> xMemberInt = ScUnoHelpFunctions::AnyToInterface(
+ xMembers->getByName( aMemberName ) );
+ (*i)->WriteToSource( xMemberInt, nPosition );
+
+ if ( nPosition >= 0 )
+ ++nPosition; // increase if initialized
+ }
+ // missing member is no error
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ScDPSaveData::ScDPSaveData() :
+ pDimensionData( NULL ),
+ nColumnGrandMode( SC_DPSAVEMODE_DONTKNOW ),
+ nRowGrandMode( SC_DPSAVEMODE_DONTKNOW ),
+ nIgnoreEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
+ nRepeatEmptyMode( SC_DPSAVEMODE_DONTKNOW ),
+ bFilterButton( TRUE ),
+ bDrillDown( TRUE )
+{
+}
+
+ScDPSaveData::ScDPSaveData(const ScDPSaveData& r) :
+ nColumnGrandMode( r.nColumnGrandMode ),
+ nRowGrandMode( r.nRowGrandMode ),
+ nIgnoreEmptyMode( r.nIgnoreEmptyMode ),
+ nRepeatEmptyMode( r.nRepeatEmptyMode ),
+ bFilterButton( r.bFilterButton ),
+ bDrillDown( r.bDrillDown )
+{
+ if ( r.pDimensionData )
+ pDimensionData = new ScDPDimensionSaveData( *r.pDimensionData );
+ else
+ pDimensionData = NULL;
+
+ long nCount = r.aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pNew = new ScDPSaveDimension( *(ScDPSaveDimension*)r.aDimList.GetObject(i) );
+ aDimList.Insert( pNew, LIST_APPEND );
+ }
+}
+
+ScDPSaveData& ScDPSaveData::operator= ( const ScDPSaveData& r )
+{
+ if ( &r != this )
+ {
+ delete pDimensionData;
+ if ( r.pDimensionData )
+ pDimensionData = new ScDPDimensionSaveData( *r.pDimensionData );
+ else
+ pDimensionData = NULL;
+
+ nColumnGrandMode = r.nColumnGrandMode;
+ nRowGrandMode = r.nRowGrandMode;
+ nIgnoreEmptyMode = r.nIgnoreEmptyMode;
+ nRepeatEmptyMode = r.nRepeatEmptyMode;
+ bFilterButton = r.bFilterButton;
+ bDrillDown = r.bDrillDown;
+
+ // remove old dimensions
+
+ long nCount = aDimList.Count();
+ long i;
+ for (i=0; i<nCount; i++)
+ delete (ScDPSaveDimension*)aDimList.GetObject(i);
+ aDimList.Clear();
+
+ // copy new dimensions
+
+ nCount = r.aDimList.Count();
+ for (i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pNew =
+ new ScDPSaveDimension( *(ScDPSaveDimension*)r.aDimList.GetObject(i) );
+ aDimList.Insert( pNew, LIST_APPEND );
+ }
+ }
+ return *this;
+}
+
+BOOL ScDPSaveData::operator== ( const ScDPSaveData& r ) const
+{
+ if ( nColumnGrandMode != r.nColumnGrandMode ||
+ nRowGrandMode != r.nRowGrandMode ||
+ nIgnoreEmptyMode != r.nIgnoreEmptyMode ||
+ nRepeatEmptyMode != r.nRepeatEmptyMode ||
+ bFilterButton != r.bFilterButton ||
+ bDrillDown != r.bDrillDown )
+ return FALSE;
+
+ if ( pDimensionData || r.pDimensionData )
+ if ( !pDimensionData || !r.pDimensionData || !( *pDimensionData == *r.pDimensionData ) )
+ return FALSE;
+
+ ULONG nCount = aDimList.Count();
+ if ( nCount != r.aDimList.Count() )
+ return FALSE;
+
+ for (ULONG i=0; i<nCount; i++)
+ if ( !( *(ScDPSaveDimension*)aDimList.GetObject(i) ==
+ *(ScDPSaveDimension*)r.aDimList.GetObject(i) ) )
+ return FALSE;
+
+ return TRUE;
+}
+
+ScDPSaveData::~ScDPSaveData()
+{
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ delete (ScDPSaveDimension*)aDimList.GetObject(i);
+ aDimList.Clear();
+
+ delete pDimensionData;
+}
+
+ScDPSaveDimension* ScDPSaveData::GetDimensionByName(const String& rName)
+{
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i);
+ if ( pDim->GetName() == rName && !pDim->IsDataLayout() )
+ return pDim;
+ }
+ ScDPSaveDimension* pNew = new ScDPSaveDimension( rName, FALSE );
+ aDimList.Insert( pNew, LIST_APPEND );
+ return pNew;
+}
+
+ScDPSaveDimension* ScDPSaveData::GetExistingDimensionByName(const String& rName)
+{
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i);
+ if ( pDim->GetName() == rName && !pDim->IsDataLayout() )
+ return pDim;
+ }
+ return NULL; // don't create new
+}
+
+ScDPSaveDimension* ScDPSaveData::GetNewDimensionByName(const String& rName)
+{
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i);
+ if ( pDim->GetName() == rName && !pDim->IsDataLayout() )
+ return DuplicateDimension(rName);
+ }
+ ScDPSaveDimension* pNew = new ScDPSaveDimension( rName, FALSE );
+ aDimList.Insert( pNew, LIST_APPEND );
+ return pNew;
+}
+
+ScDPSaveDimension* ScDPSaveData::GetDataLayoutDimension()
+{
+ ULONG nCount = aDimList.Count();
+ for (ULONG i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i);
+ if ( pDim->IsDataLayout() )
+ return pDim;
+ }
+ ScDPSaveDimension* pNew = new ScDPSaveDimension( String(), TRUE );
+ aDimList.Insert( pNew, LIST_APPEND );
+ return pNew;
+}
+
+ScDPSaveDimension* ScDPSaveData::DuplicateDimension(const String& rName)
+{
+ // always insert new
+ //! check if dimension is there?
+
+ ScDPSaveDimension* pOld = GetDimensionByName( rName );
+ ScDPSaveDimension* pNew = new ScDPSaveDimension( *pOld );
+ pNew->SetDupFlag( TRUE );
+ aDimList.Insert( pNew, LIST_APPEND );
+ return pNew;
+}
+
+void ScDPSaveData::RemoveDimensionByName(const String& rName)
+{
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i);
+ if ( pDim->GetName() == rName && !pDim->IsDataLayout() )
+ {
+ delete pDim;
+ aDimList.Remove(i);
+ break;
+ }
+ }
+}
+
+ScDPSaveDimension& ScDPSaveData::DuplicateDimension( const ScDPSaveDimension& rDim )
+{
+ ScDPSaveDimension* pNew = new ScDPSaveDimension( rDim );
+ pNew->SetDupFlag( TRUE );
+ aDimList.Insert( pNew, LIST_APPEND );
+ return *pNew;
+}
+
+ScDPSaveDimension* ScDPSaveData::GetInnermostDimension(USHORT nOrientation)
+{
+ // return the innermost dimension for the given orientation,
+ // excluding data layout dimension
+
+ ScDPSaveDimension* pInner = NULL;
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pDim = static_cast<ScDPSaveDimension*>(aDimList.GetObject(i));
+ if ( pDim->GetOrientation() == nOrientation && !pDim->IsDataLayout() )
+ pInner = pDim;
+ }
+ return pInner; // the last matching one
+}
+
+long ScDPSaveData::GetDataDimensionCount() const
+{
+ long nDataCount = 0;
+
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ const ScDPSaveDimension* pDim = static_cast<const ScDPSaveDimension*>(aDimList.GetObject(i));
+ if ( pDim->GetOrientation() == sheet::DataPilotFieldOrientation_DATA )
+ ++nDataCount;
+ }
+
+ return nDataCount;
+}
+
+void ScDPSaveData::SetPosition( ScDPSaveDimension* pDim, long nNew )
+{
+ // position (nNew) is counted within dimensions of the same orientation
+
+ USHORT nOrient = pDim->GetOrientation();
+
+ aDimList.Remove( pDim );
+ ULONG nCount = aDimList.Count(); // after remove
+
+ ULONG nInsPos = 0;
+ while ( nNew > 0 && nInsPos < nCount )
+ {
+ if ( ((ScDPSaveDimension*)aDimList.GetObject(nInsPos))->GetOrientation() == nOrient )
+ --nNew;
+ ++nInsPos;
+ }
+
+ aDimList.Insert( pDim, nInsPos );
+}
+
+void ScDPSaveData::SetColumnGrand(BOOL bSet)
+{
+ nColumnGrandMode = bSet;
+}
+
+void ScDPSaveData::SetRowGrand(BOOL bSet)
+{
+ nRowGrandMode = bSet;
+}
+
+void ScDPSaveData::SetIgnoreEmptyRows(BOOL bSet)
+{
+ nIgnoreEmptyMode = bSet;
+}
+
+void ScDPSaveData::SetRepeatIfEmpty(BOOL bSet)
+{
+ nRepeatEmptyMode = bSet;
+}
+
+void ScDPSaveData::SetFilterButton(BOOL bSet)
+{
+ bFilterButton = bSet;
+}
+
+void ScDPSaveData::SetDrillDown(BOOL bSet)
+{
+ bDrillDown = bSet;
+}
+
+void lcl_ResetOrient( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
+{
+ sheet::DataPilotFieldOrientation eOrient = sheet::DataPilotFieldOrientation_HIDDEN;
+
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ long nIntCount = xIntDims->getCount();
+ for (long nIntDim=0; nIntDim<nIntCount; nIntDim++)
+ {
+ uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+ if (xDimProp.is())
+ {
+ uno::Any aAny;
+ aAny <<= eOrient;
+ xDimProp->setPropertyValue( rtl::OUString::createFromAscii(DP_PROP_ORIENTATION), aAny );
+ }
+ }
+}
+
+void ScDPSaveData::WriteToSource( const uno::Reference<sheet::XDimensionsSupplier>& xSource )
+{
+ if (!xSource.is())
+ return;
+
+ // source options must be first!
+
+ uno::Reference<beans::XPropertySet> xSourceProp( xSource, uno::UNO_QUERY );
+ DBG_ASSERT( xSourceProp.is(), "no properties at source" );
+ if ( xSourceProp.is() )
+ {
+ // source options are not available for external sources
+ //! use XPropertySetInfo to test for availability?
+
+ try
+ {
+ if ( nIgnoreEmptyMode != SC_DPSAVEMODE_DONTKNOW )
+ lcl_SetBoolProperty( xSourceProp,
+ rtl::OUString::createFromAscii(DP_PROP_IGNOREEMPTY), (BOOL)nIgnoreEmptyMode );
+ if ( nRepeatEmptyMode != SC_DPSAVEMODE_DONTKNOW )
+ lcl_SetBoolProperty( xSourceProp,
+ rtl::OUString::createFromAscii(DP_PROP_REPEATIFEMPTY), (BOOL)nRepeatEmptyMode );
+ }
+ catch(uno::Exception&)
+ {
+ // no error
+ }
+ }
+
+ // exceptions in the other calls are errors
+ try
+ {
+ // reset all orientations
+ //! "forgetSettings" or similar at source ?????
+ //! reset all duplicated dimensions, or reuse them below !!!
+
+ lcl_ResetOrient( xSource );
+
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i);
+ rtl::OUString aName = pDim->GetName();
+ BOOL bData = pDim->IsDataLayout();
+
+ //! getByName for ScDPSource, including DataLayoutDimension !!!!!!!!
+
+ uno::Reference<container::XNameAccess> xDimsName = xSource->getDimensions();
+ uno::Reference<container::XIndexAccess> xIntDims = new ScNameToIndexAccess( xDimsName );
+ long nIntCount = xIntDims->getCount();
+ BOOL bFound = FALSE;
+ for (long nIntDim=0; nIntDim<nIntCount && !bFound; nIntDim++)
+ {
+ uno::Reference<uno::XInterface> xIntDim = ScUnoHelpFunctions::AnyToInterface( xIntDims->getByIndex(nIntDim) );
+ if ( bData )
+ {
+ uno::Reference<beans::XPropertySet> xDimProp( xIntDim, uno::UNO_QUERY );
+ if ( xDimProp.is() )
+ {
+ bFound = ScUnoHelpFunctions::GetBoolProperty( xDimProp,
+ rtl::OUString::createFromAscii(DP_PROP_ISDATALAYOUT) );
+ //! error checking -- is "IsDataLayoutDimension" property required??
+ }
+ }
+ else
+ {
+ uno::Reference<container::XNamed> xDimName( xIntDim, uno::UNO_QUERY );
+ if ( xDimName.is() && xDimName->getName() == aName )
+ bFound = TRUE;
+ }
+
+ if ( bFound )
+ {
+ if ( pDim->GetDupFlag() )
+ {
+ String aNewName = pDim->GetName();
+
+ // different name for each duplication of a (real) dimension...
+ for (long j=0; j<=i; j++) //! Test !!!!!!
+ aNewName += '*'; //! modify name at creation of SaveDimension
+
+ uno::Reference<util::XCloneable> xCloneable( xIntDim, uno::UNO_QUERY );
+ DBG_ASSERT( xCloneable.is(), "cannot clone dimension" );
+ if (xCloneable.is())
+ {
+ uno::Reference<util::XCloneable> xNew = xCloneable->createClone();
+ uno::Reference<container::XNamed> xNewName( xNew, uno::UNO_QUERY );
+ if (xNewName.is())
+ {
+ xNewName->setName( aNewName );
+ pDim->WriteToSource( xNew );
+ }
+ }
+ }
+ else
+ pDim->WriteToSource( xIntDim );
+ }
+ }
+ DBG_ASSERT(bFound, "WriteToSource: Dimension not found");
+ }
+
+ if ( xSourceProp.is() )
+ {
+ if ( nColumnGrandMode != SC_DPSAVEMODE_DONTKNOW )
+ lcl_SetBoolProperty( xSourceProp,
+ rtl::OUString::createFromAscii(DP_PROP_COLUMNGRAND), (BOOL)nColumnGrandMode );
+ if ( nRowGrandMode != SC_DPSAVEMODE_DONTKNOW )
+ lcl_SetBoolProperty( xSourceProp,
+ rtl::OUString::createFromAscii(DP_PROP_ROWGRAND), (BOOL)nRowGrandMode );
+ }
+ }
+ catch(uno::Exception&)
+ {
+ DBG_ERROR("exception in WriteToSource");
+ }
+}
+
+BOOL ScDPSaveData::IsEmpty() const
+{
+ long nCount = aDimList.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPSaveDimension* pDim = (ScDPSaveDimension*)aDimList.GetObject(i);
+ if ( pDim->GetOrientation() != sheet::DataPilotFieldOrientation_HIDDEN && !pDim->IsDataLayout() )
+ return FALSE;
+ }
+ return TRUE; // no entries that are not hidden
+}
+
+ScDPDimensionSaveData* ScDPSaveData::GetDimensionData()
+{
+ if (!pDimensionData)
+ pDimensionData = new ScDPDimensionSaveData;
+ return pDimensionData;
+}
+
+void ScDPSaveData::SetDimensionData( const ScDPDimensionSaveData* pNew )
+{
+ delete pDimensionData;
+ if ( pNew )
+ pDimensionData = new ScDPDimensionSaveData( *pNew );
+ else
+ pDimensionData = NULL;
+}
+
diff --git a/sc/source/core/data/dpsdbtab.cxx b/sc/source/core/data/dpsdbtab.cxx
new file mode 100644
index 000000000000..777ea3f38935
--- /dev/null
+++ b/sc/source/core/data/dpsdbtab.cxx
@@ -0,0 +1,330 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dpsdbtab.cxx,v $
+ * $Revision: 1.15 $
+ *
+ * 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 --------------------------------------------------------------
+
+#include <tools/debug.hxx>
+#include <vcl/msgbox.hxx>
+#include <svtools/zforlist.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/types.hxx>
+
+#include <com/sun/star/sheet/DataImportMode.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/XCompletedExecution.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+
+#include "dpsdbtab.hxx"
+#include "collect.hxx"
+#include "global.hxx"
+#include "globstr.hrc"
+#include "dpcachetable.hxx"
+#include "dptabres.hxx"
+#include "document.hxx"
+#include "dpobject.hxx"
+
+using namespace com::sun::star;
+
+using ::std::vector;
+using ::std::hash_map;
+using ::std::hash_set;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::UNO_QUERY;
+
+#define SC_SERVICE_ROWSET "com.sun.star.sdb.RowSet"
+#define SC_SERVICE_INTHANDLER "com.sun.star.sdb.InteractionHandler"
+
+//! move to a header file?
+#define SC_DBPROP_DATASOURCENAME "DataSourceName"
+#define SC_DBPROP_COMMAND "Command"
+#define SC_DBPROP_COMMANDTYPE "CommandType"
+
+// -----------------------------------------------------------------------
+
+class ScDatabaseDPData_Impl
+{
+public:
+ ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xServiceManager;
+ ScImportSourceDesc aDesc;
+ long nColCount;
+ uno::Reference<sdbc::XRowSet> xRowSet;
+ sal_Int32* pTypes;
+ SvNumberFormatter* pFormatter;
+
+ ScDPCacheTable aCacheTable;
+
+ ScDatabaseDPData_Impl(ScDPCollection* p) :
+ aCacheTable(p)
+ {
+ }
+};
+
+// -----------------------------------------------------------------------
+
+ScDatabaseDPData::ScDatabaseDPData(
+ ScDocument* pDoc,
+ const ScImportSourceDesc& rImport ) :
+ ScDPTableData(pDoc)
+{
+ pImpl = new ScDatabaseDPData_Impl(pDoc->GetDPCollection());
+ pImpl->xServiceManager = pDoc->GetServiceManager();
+ pImpl->aDesc = rImport;
+ pImpl->nColCount = 0;
+ pImpl->pTypes = NULL;
+ pImpl->pFormatter = NULL; // created on demand
+
+ OpenDatabase();
+ CreateCacheTable();
+}
+
+ScDatabaseDPData::~ScDatabaseDPData()
+{
+ ::comphelper::disposeComponent( pImpl->xRowSet );
+
+ delete[] pImpl->pTypes;
+ delete pImpl->pFormatter; // NumberFormatter is local for this object
+ delete pImpl;
+}
+
+void ScDatabaseDPData::DisposeData()
+{
+ //! use OpenDatabase here?
+ pImpl->aCacheTable.clear();
+}
+
+BOOL ScDatabaseDPData::OpenDatabase()
+{
+ sal_Int32 nSdbType = -1;
+ switch ( pImpl->aDesc.nType )
+ {
+ case sheet::DataImportMode_SQL: nSdbType = sdb::CommandType::COMMAND; break;
+ case sheet::DataImportMode_TABLE: nSdbType = sdb::CommandType::TABLE; break;
+ case sheet::DataImportMode_QUERY: nSdbType = sdb::CommandType::QUERY; break;
+ default:
+ return FALSE;
+ }
+
+ BOOL bSuccess = FALSE;
+ try
+ {
+ pImpl->xRowSet = uno::Reference<sdbc::XRowSet>(
+ comphelper::getProcessServiceFactory()->createInstance(
+ rtl::OUString::createFromAscii( SC_SERVICE_ROWSET ) ),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xRowProp( pImpl->xRowSet, uno::UNO_QUERY );
+ DBG_ASSERT( xRowProp.is(), "can't get RowSet" );
+ if ( xRowProp.is() )
+ {
+ //
+ // set source parameters
+ //
+
+ uno::Any aAny;
+
+ aAny <<= rtl::OUString( pImpl->aDesc.aDBName );
+ xRowProp->setPropertyValue(
+ rtl::OUString::createFromAscii(SC_DBPROP_DATASOURCENAME), aAny );
+
+ aAny <<= rtl::OUString( pImpl->aDesc.aObject );
+ xRowProp->setPropertyValue(
+ rtl::OUString::createFromAscii(SC_DBPROP_COMMAND), aAny );
+
+ aAny <<= nSdbType;
+ xRowProp->setPropertyValue(
+ rtl::OUString::createFromAscii(SC_DBPROP_COMMANDTYPE), aAny );
+
+ uno::Reference<sdb::XCompletedExecution> xExecute( pImpl->xRowSet, uno::UNO_QUERY );
+ if ( xExecute.is() )
+ {
+ uno::Reference<task::XInteractionHandler> xHandler(
+ comphelper::getProcessServiceFactory()->createInstance(
+ rtl::OUString::createFromAscii( SC_SERVICE_INTHANDLER ) ),
+ uno::UNO_QUERY);
+ xExecute->executeWithCompletion( xHandler );
+ }
+ else
+ pImpl->xRowSet->execute();
+
+ //
+ // get column descriptions
+ //
+
+ pImpl->nColCount = 0;
+ uno::Reference<sdbc::XResultSetMetaData> xMeta;
+ uno::Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp( pImpl->xRowSet, uno::UNO_QUERY );
+ if ( xMetaSupp.is() )
+ xMeta = xMetaSupp->getMetaData();
+ if ( xMeta.is() )
+ pImpl->nColCount = xMeta->getColumnCount(); // this is the number of real columns
+
+ uno::Reference<sdbc::XResultSet> xResSet( pImpl->xRowSet, uno::UNO_QUERY );
+ if ( pImpl->nColCount > 0 && xResSet.is() )
+ {
+ pImpl->pTypes = new sal_Int32[pImpl->nColCount];
+ for (long nCol=0; nCol<pImpl->nColCount; nCol++)
+ pImpl->pTypes[nCol] = xMeta->getColumnType( nCol+1 );
+
+ bSuccess = TRUE;
+ }
+ }
+ }
+ catch ( sdbc::SQLException& rError )
+ {
+ //! store error message
+ InfoBox aInfoBox( 0, String(rError.Message) );
+ aInfoBox.Execute();
+ }
+ catch ( uno::Exception& )
+ {
+ DBG_ERROR("Unexpected exception in database");
+ }
+
+
+ if (!bSuccess)
+ ::comphelper::disposeComponent( pImpl->xRowSet );
+
+ return bSuccess;
+}
+
+long ScDatabaseDPData::GetColumnCount()
+{
+ return pImpl->nColCount;
+}
+
+void lcl_Reset( const uno::Reference<sdbc::XRowSet>& xRowSet )
+ throw(sdbc::SQLException, uno::RuntimeException)
+{
+ // isBeforeFirst / beforeFirst is not always available
+ //! query if it is allowed
+
+ xRowSet->execute(); // restart
+}
+
+const TypedScStrCollection& ScDatabaseDPData::GetColumnEntries(long nColumn)
+{
+ CreateCacheTable();
+ return pImpl->aCacheTable.getFieldEntries(nColumn);
+}
+
+String ScDatabaseDPData::getDimensionName(long nColumn)
+{
+ if (getIsDataLayoutDimension(nColumn))
+ {
+ //! different internal and display names?
+ //return "Data";
+ return ScGlobal::GetRscString(STR_PIVOT_DATA);
+ }
+
+ CreateCacheTable();
+ const String* pStr = pImpl->aCacheTable.getFieldName(nColumn);
+ if (pStr)
+ return *pStr;
+
+ DBG_ERROR("getDimensionName: invalid dimension");
+ return String();
+}
+
+BOOL ScDatabaseDPData::getIsDataLayoutDimension(long nColumn)
+{
+ return ( nColumn == pImpl->nColCount );
+}
+
+BOOL ScDatabaseDPData::IsDateDimension(long /* nDim */)
+{
+ //! later...
+ return FALSE;
+}
+
+void ScDatabaseDPData::SetEmptyFlags( BOOL /* bIgnoreEmptyRows */, BOOL /* bRepeatIfEmpty */ )
+{
+ // not used for database data
+ //! disable flags
+}
+
+void ScDatabaseDPData::CreateCacheTable()
+{
+ if (!pImpl->aCacheTable.empty())
+ return;
+
+ // Get null date.
+ if (!pImpl->pFormatter)
+ pImpl->pFormatter = new SvNumberFormatter(pImpl->xServiceManager, ScGlobal::eLnge);
+
+ pImpl->aCacheTable.fillTable(pImpl->xRowSet, *pImpl->pFormatter->GetNullDate());
+}
+
+void ScDatabaseDPData::FilterCacheTable(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims)
+{
+ CreateCacheTable();
+ pImpl->aCacheTable.filterByPageDimension(
+ rCriteria, (IsRepeatIfEmpty() ? rCatDims : hash_set<sal_Int32>()));
+}
+
+void ScDatabaseDPData::GetDrillDownData(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
+{
+ CreateCacheTable();
+ sal_Int32 nRowSize = pImpl->aCacheTable.getRowSize();
+ if (!nRowSize)
+ return;
+
+ pImpl->aCacheTable.filterTable(
+ rCriteria, rData, IsRepeatIfEmpty() ? rCatDims : hash_set<sal_Int32>());
+}
+
+void ScDatabaseDPData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
+{
+ CreateCacheTable();
+ CalcResultsFromCacheTable(pImpl->aCacheTable, rInfo, bAutoShow);
+}
+
+const ScDPCacheTable& ScDatabaseDPData::GetCacheTable() const
+{
+ return pImpl->aCacheTable;
+}
+
+// -----------------------------------------------------------------------
+
+
+
+
+
diff --git a/sc/source/core/data/dpshttab.cxx b/sc/source/core/data/dpshttab.cxx
new file mode 100644
index 000000000000..1e8c5627ee19
--- /dev/null
+++ b/sc/source/core/data/dpshttab.cxx
@@ -0,0 +1,308 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dpshttab.cxx,v $
+ * $Revision: 1.12 $
+ *
+ * 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 --------------------------------------------------------------
+
+#include <tools/debug.hxx>
+#include <svtools/zforlist.hxx>
+
+#include "dpshttab.hxx"
+#include "dptabres.hxx"
+#include "document.hxx"
+#include "collect.hxx"
+#include "cell.hxx"
+#include "dpcachetable.hxx"
+#include "dpobject.hxx"
+#include "globstr.hrc"
+
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+
+#include <vector>
+#include <set>
+
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Sequence;
+using ::std::vector;
+using ::std::hash_map;
+using ::std::hash_set;
+
+// -----------------------------------------------------------------------
+
+class ScSheetDPData_Impl
+{
+public:
+ ScDocument* pDoc;
+ ScRange aRange;
+ ScQueryParam aQuery;
+ BOOL* pSpecial; // to flag special handling of query parameters in ValidQuery.
+ BOOL bIgnoreEmptyRows;
+ BOOL bRepeatIfEmpty;
+ BOOL* pDateDim;
+ SCROW nNextRow; // for iterator, within range
+
+ ScDPCacheTable aCacheTable;
+
+ ScSheetDPData_Impl(ScDPCollection* p) :
+ pSpecial(NULL),
+ aCacheTable(p)
+ {
+ }
+};
+
+// -----------------------------------------------------------------------
+
+ScSheetDPData::ScSheetDPData( ScDocument* pD, const ScSheetSourceDesc& rDesc ) :
+ ScDPTableData(pD)
+{
+ pImpl = new ScSheetDPData_Impl(pD->GetDPCollection());
+ pImpl->pDoc = pD;
+ pImpl->aRange = rDesc.aSourceRange;
+ pImpl->aQuery = rDesc.aQueryParam;
+ pImpl->bIgnoreEmptyRows = FALSE;
+ pImpl->bRepeatIfEmpty = FALSE;
+ pImpl->pDateDim = NULL;
+
+ pImpl->nNextRow = pImpl->aRange.aStart.Row() + 1;
+
+ SCSIZE nEntryCount(pImpl->aQuery.GetEntryCount());
+ pImpl->pSpecial = new BOOL[nEntryCount];
+ for (SCSIZE j = 0; j < nEntryCount; ++j )
+ {
+ ScQueryEntry& rEntry = pImpl->aQuery.GetEntry(j);
+ if (rEntry.bDoQuery)
+ {
+ pImpl->pSpecial[j] = false;
+ if (!rEntry.bQueryByString)
+ {
+ if (*rEntry.pStr == EMPTY_STRING &&
+ ((rEntry.nVal == SC_EMPTYFIELDS) || (rEntry.nVal == SC_NONEMPTYFIELDS)))
+ pImpl->pSpecial[j] = true;
+ }
+ else
+ {
+ sal_uInt32 nIndex = 0;
+ rEntry.bQueryByString =
+ !(pD->GetFormatTable()->
+ IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal));
+ }
+ }
+ }
+}
+
+ScSheetDPData::~ScSheetDPData()
+{
+ delete[] pImpl->pDateDim;
+ delete[] pImpl->pSpecial;
+ delete pImpl;
+}
+
+void ScSheetDPData::DisposeData()
+{
+ pImpl->aCacheTable.clear();
+}
+
+long ScSheetDPData::GetColumnCount()
+{
+ CreateCacheTable();
+ return pImpl->aCacheTable.getColSize();
+}
+
+BOOL lcl_HasQuery( const ScQueryParam& rParam )
+{
+ return rParam.GetEntryCount() > 0 &&
+ rParam.GetEntry(0).bDoQuery;
+}
+
+const TypedScStrCollection& ScSheetDPData::GetColumnEntries(long nColumn)
+{
+ DBG_ASSERT(nColumn>=0 && nColumn < pImpl->aCacheTable.getColSize(), "ScSheetDPData: wrong column");
+ CreateCacheTable();
+ return pImpl->aCacheTable.getFieldEntries(nColumn);
+}
+
+String ScSheetDPData::getDimensionName(long nColumn)
+{
+ CreateCacheTable();
+ if (getIsDataLayoutDimension(nColumn))
+ {
+ //! different internal and display names?
+ //return "Data";
+ return ScGlobal::GetRscString(STR_PIVOT_DATA);
+ }
+ else if (nColumn >= pImpl->aCacheTable.getColSize())
+ {
+ DBG_ERROR("getDimensionName: invalid dimension");
+ return String();
+ }
+ else
+ {
+ const String* pStr = pImpl->aCacheTable.getFieldName(nColumn);
+ if (pStr)
+ return *pStr;
+ else return String();
+ }
+}
+
+BOOL lcl_HasDateFormat( ScDocument* pDoc, const ScRange& rRange )
+{
+ //! iterate formats in range?
+
+ ScAddress aPos = rRange.aStart;
+ aPos.SetRow( aPos.Row() + 1 ); // below title
+ ULONG nFormat = pDoc->GetNumberFormat( aPos );
+ SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
+ return ( pFormatter->GetType(nFormat) & NUMBERFORMAT_DATE ) != 0;
+}
+
+BOOL ScSheetDPData::IsDateDimension(long nDim)
+{
+ CreateCacheTable();
+ long nColCount = pImpl->aCacheTable.getColSize();
+ if (getIsDataLayoutDimension(nDim))
+ {
+ return FALSE;
+ }
+ else if (nDim >= nColCount)
+ {
+ DBG_ERROR("IsDateDimension: invalid dimension");
+ return FALSE;
+ }
+ else
+ {
+ if (!pImpl->pDateDim)
+ {
+ pImpl->pDateDim = new BOOL[nColCount];
+ ScRange aTestRange = pImpl->aRange;
+ for (long i = 0; i < nColCount; ++i)
+ {
+ SCCOL nCol = (SCCOL)( pImpl->aRange.aStart.Col() + i );
+ aTestRange.aStart.SetCol(nCol);
+ aTestRange.aEnd.SetCol(nCol);
+ pImpl->pDateDim[i] = lcl_HasDateFormat( pImpl->pDoc, aTestRange );
+ }
+ }
+ return pImpl->pDateDim[nDim];
+ }
+}
+
+UINT32 ScSheetDPData::GetNumberFormat(long nDim)
+{
+ CreateCacheTable();
+ if (getIsDataLayoutDimension(nDim))
+ {
+ return 0;
+ }
+ else if (nDim >= pImpl->aCacheTable.getColSize())
+ {
+ DBG_ERROR("GetNumberFormat: invalid dimension");
+ return 0;
+ }
+ else
+ {
+ // is queried only once per dimension from ScDPOutput -> no need to cache
+
+ ScAddress aPos = pImpl->aRange.aStart;
+ aPos.SetCol( sal::static_int_cast<SCCOL>( aPos.Col() + nDim ) );
+ aPos.SetRow( aPos.Row() + 1 ); // below title
+ return pImpl->pDoc->GetNumberFormat( aPos );
+ }
+}
+
+BOOL ScSheetDPData::getIsDataLayoutDimension(long nColumn)
+{
+ CreateCacheTable();
+ return (nColumn == pImpl->aCacheTable.getColSize());
+}
+
+void ScSheetDPData::SetEmptyFlags( BOOL bIgnoreEmptyRows, BOOL bRepeatIfEmpty )
+{
+ pImpl->bIgnoreEmptyRows = bIgnoreEmptyRows;
+ pImpl->bRepeatIfEmpty = bRepeatIfEmpty;
+}
+
+bool ScSheetDPData::IsRepeatIfEmpty()
+{
+ return pImpl->bRepeatIfEmpty;
+}
+
+void ScSheetDPData::CreateCacheTable()
+{
+ // Scan and store the data from the source range.
+ if (!pImpl->aCacheTable.empty())
+ // already cached.
+ return;
+
+ pImpl->aCacheTable.fillTable(pImpl->pDoc, pImpl->aRange, pImpl->aQuery, pImpl->pSpecial,
+ pImpl->bIgnoreEmptyRows);
+}
+
+void ScSheetDPData::FilterCacheTable(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims)
+{
+ CreateCacheTable();
+ pImpl->aCacheTable.filterByPageDimension(
+ rCriteria, (IsRepeatIfEmpty() ? rCatDims : hash_set<sal_Int32>()));
+}
+
+void ScSheetDPData::GetDrillDownData(const vector<ScDPCacheTable::Criterion>& rCriteria, const hash_set<sal_Int32>& rCatDims, Sequence< Sequence<Any> >& rData)
+{
+ CreateCacheTable();
+ sal_Int32 nRowSize = pImpl->aCacheTable.getRowSize();
+ if (!nRowSize)
+ return;
+
+ pImpl->aCacheTable.filterTable(
+ rCriteria, rData, IsRepeatIfEmpty() ? rCatDims : hash_set<sal_Int32>());
+}
+
+void ScSheetDPData::CalcResults(CalcInfo& rInfo, bool bAutoShow)
+{
+ CreateCacheTable();
+ CalcResultsFromCacheTable(pImpl->aCacheTable, rInfo, bAutoShow);
+}
+
+const ScDPCacheTable& ScSheetDPData::GetCacheTable() const
+{
+ return pImpl->aCacheTable;
+}
+
+// -----------------------------------------------------------------------
+
+
+
+
+
+
+
diff --git a/sc/source/core/data/dptabdat.cxx b/sc/source/core/data/dptabdat.cxx
new file mode 100644
index 000000000000..a58241cea416
--- /dev/null
+++ b/sc/source/core/data/dptabdat.cxx
@@ -0,0 +1,336 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dptabdat.cxx,v $
+ * $Revision: 1.18 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <stdio.h>
+#include <rtl/math.hxx>
+#include <tools/debug.hxx>
+#include <tools/date.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <unotools/collatorwrapper.hxx>
+
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+
+#include "dptabdat.hxx"
+#include "global.hxx"
+#include "dpcachetable.hxx"
+#include "dptabres.hxx"
+#include "document.hxx"
+#include "dpobject.hxx"
+
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Any;
+using ::std::vector;
+using ::std::set;
+using ::std::hash_map;
+
+// -----------------------------------------------------------------------
+
+BOOL ScDPItemData::IsCaseInsEqual( const ScDPItemData& r ) const
+{
+ //! pass Transliteration?
+ //! inline?
+ return bHasValue ? ( r.bHasValue && rtl::math::approxEqual( fValue, r.fValue ) ) :
+ ( !r.bHasValue &&
+ ScGlobal::pTransliteration->isEqual( aString, r.aString ) );
+}
+
+size_t ScDPItemData::Hash() const
+{
+ if ( bHasValue )
+ return (size_t) rtl::math::approxFloor( fValue );
+ else
+ // If we do unicode safe case insensitive hash we can drop
+ // ScDPItemData::operator== and use ::IsCasInsEqual
+ return rtl_ustr_hashCode_WithLength( aString.GetBuffer(), aString.Len() );
+}
+
+BOOL ScDPItemData::operator==( const ScDPItemData& r ) const
+{
+ if ( bHasValue )
+ {
+ if ( r.bHasValue )
+ return rtl::math::approxEqual( fValue, r.fValue );
+ else
+ return FALSE;
+ }
+ else if ( r.bHasValue )
+ return FALSE;
+ else
+ // need exact equality until we have a safe case insensitive string hash
+ return aString == r.aString;
+}
+
+sal_Int32 ScDPItemData::Compare( const ScDPItemData& rA,
+ const ScDPItemData& rB )
+{
+ if ( rA.bHasValue )
+ {
+ if ( rB.bHasValue )
+ {
+ if ( rtl::math::approxEqual( rA.fValue, rB.fValue ) )
+ return 0;
+ else if ( rA.fValue < rB.fValue )
+ return -1;
+ else
+ return 1;
+ }
+ else
+ return -1; // values first
+ }
+ else if ( rB.bHasValue )
+ return 1; // values first
+ else
+ return ScGlobal::pCollator->compareString( rA.aString, rB.aString );
+}
+
+// ---------------------------------------------------------------------------
+
+ScDPTableData::CalcInfo::CalcInfo() :
+ bRepeatIfEmpty(false)
+{
+}
+
+// ---------------------------------------------------------------------------
+
+ScDPTableData::ScDPTableData(ScDocument* pDoc) :
+ mrSharedString(pDoc->GetDPCollection()->GetSharedString())
+{
+ nLastDateVal = nLastHier = nLastLevel = nLastRet = -1; // invalid
+
+ //! reset before new calculation (in case the base date is changed)
+}
+
+ScDPTableData::~ScDPTableData()
+{
+}
+
+long ScDPTableData::GetDatePart( long nDateVal, long nHierarchy, long nLevel )
+{
+ if ( nDateVal == nLastDateVal && nHierarchy == nLastHier && nLevel == nLastLevel )
+ return nLastRet;
+
+ Date aDate( 30,12,1899 ); //! get from source data (and cache here)
+ aDate += nDateVal;
+
+ long nRet = 0;
+ switch (nHierarchy)
+ {
+ case SC_DAPI_HIERARCHY_QUARTER:
+ switch (nLevel)
+ {
+ case 0: nRet = aDate.GetYear(); break;
+ case 1: nRet = (aDate.GetMonth()-1) / 3 + 1; break;
+ case 2: nRet = aDate.GetMonth(); break;
+ case 3: nRet = aDate.GetDay(); break;
+ default:
+ DBG_ERROR("GetDatePart: wrong level");
+ }
+ break;
+ case SC_DAPI_HIERARCHY_WEEK:
+ switch (nLevel)
+ {
+ //! use settings for different definitions
+ case 0: nRet = aDate.GetYear(); break; //!...
+ case 1: nRet = aDate.GetWeekOfYear(); break;
+ case 2: nRet = (long)aDate.GetDayOfWeek(); break;
+ default:
+ DBG_ERROR("GetDatePart: wrong level");
+ }
+ break;
+ default:
+ DBG_ERROR("GetDatePart: wrong hierarchy");
+ }
+
+ nLastDateVal = nDateVal;
+ nLastHier = nHierarchy;
+ nLastLevel = nLevel;
+ nLastRet = nRet;
+
+ return nRet;
+}
+
+bool ScDPTableData::IsRepeatIfEmpty()
+{
+ return false;
+}
+
+UINT32 ScDPTableData::GetNumberFormat(long)
+{
+ return 0; // default format
+}
+
+BOOL ScDPTableData::IsBaseForGroup(long) const
+{
+ return FALSE; // always false
+}
+
+long ScDPTableData::GetGroupBase(long) const
+{
+ return -1; // always none
+}
+
+BOOL ScDPTableData::IsNumOrDateGroup(long) const
+{
+ return FALSE; // always false
+}
+
+BOOL ScDPTableData::IsInGroup( const ScDPItemData&, long,
+ const ScDPItemData&, long ) const
+{
+ DBG_ERROR("IsInGroup shouldn't be called for non-group data");
+ return FALSE;
+}
+
+BOOL ScDPTableData::HasCommonElement( const ScDPItemData&, long,
+ const ScDPItemData&, long ) const
+{
+ DBG_ERROR("HasCommonElement shouldn't be called for non-group data");
+ return FALSE;
+}
+
+ScSimpleSharedString& ScDPTableData::GetSharedString()
+{
+ return mrSharedString;
+}
+
+void ScDPTableData::FillRowDataFromCacheTable(sal_Int32 nRow, const ScDPCacheTable& rCacheTable,
+ const CalcInfo& rInfo, CalcRowData& rData)
+{
+ // column dimensions
+ GetItemData(rCacheTable, nRow, rInfo.aColLevelDims, rData.aColData);
+
+ // row dimensions
+ GetItemData(rCacheTable, nRow, rInfo.aRowLevelDims, rData.aRowData);
+
+ // page dimensions
+ GetItemData(rCacheTable, nRow, rInfo.aPageDims, rData.aPageData);
+
+ sal_Int32 n = rInfo.aDataSrcCols.size();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ long nDim = rInfo.aDataSrcCols[i];
+ rData.aValues.push_back( ScDPValueData() );
+ ScDPValueData& rVal = rData.aValues.back();
+ const ScDPCacheCell* pCell = rCacheTable.getCell(
+ static_cast<SCCOL>(nDim), static_cast<SCROW>(nRow), false);
+ if (pCell)
+ {
+ rVal.fValue = pCell->mbNumeric ? pCell->mfValue : 0.0;
+ rVal.nType = pCell->mnType;
+ }
+ else
+ rVal.Set(0.0, SC_VALTYPE_EMPTY);
+ }
+}
+
+void ScDPTableData::ProcessRowData(CalcInfo& rInfo, CalcRowData& rData, bool bAutoShow)
+{
+ if (!bAutoShow)
+ {
+ rInfo.pColRoot->LateInitFrom(rInfo.aColDims, rInfo.aColLevels, rData.aColData, 0, *rInfo.pInitState);
+ rInfo.pRowRoot->LateInitFrom(rInfo.aRowDims, rInfo.aRowLevels, rData.aRowData, 0, *rInfo.pInitState);
+ }
+
+ if ( ( !rInfo.pColRoot->GetChildDimension() || rInfo.pColRoot->GetChildDimension()->IsValidEntry(rData.aColData) ) &&
+ ( !rInfo.pRowRoot->GetChildDimension() || rInfo.pRowRoot->GetChildDimension()->IsValidEntry(rData.aRowData) ) )
+ {
+ //! single process method with ColMembers, RowMembers and data !!!
+ if (rInfo.pColRoot->GetChildDimension())
+ {
+ vector<ScDPItemData> aEmptyData;
+ rInfo.pColRoot->GetChildDimension()->ProcessData(rData.aColData, NULL, aEmptyData, rData.aValues);
+ }
+
+ rInfo.pRowRoot->ProcessData(rData.aRowData, rInfo.pColRoot->GetChildDimension(),
+ rData.aColData, rData.aValues);
+ }
+}
+
+void ScDPTableData::CalcResultsFromCacheTable(const ScDPCacheTable& rCacheTable, CalcInfo& rInfo, bool bAutoShow)
+{
+ sal_Int32 nRowSize = rCacheTable.getRowSize();
+ for (sal_Int32 nRow = 0; nRow < nRowSize; ++nRow)
+ {
+ if (!rCacheTable.isRowActive(nRow))
+ continue;
+
+ CalcRowData aData;
+ FillRowDataFromCacheTable(nRow, rCacheTable, rInfo, aData);
+ ProcessRowData(rInfo, aData, bAutoShow);
+ }
+}
+
+void ScDPTableData::GetItemData(const ScDPCacheTable& rCacheTable, sal_Int32 nRow,
+ const vector<long>& rDims, vector<ScDPItemData>& rItemData)
+{
+ sal_Int32 nDimSize = rDims.size();
+ for (sal_Int32 i = 0; i < nDimSize; ++i)
+ {
+ long nDim = rDims[i];
+ rItemData.push_back( ScDPItemData() );
+ ScDPItemData& rData = rItemData.back();
+ if (getIsDataLayoutDimension(nDim))
+ {
+ rData.SetString(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("x")));
+ continue;
+ }
+
+ const ScDPCacheCell* pCell = rCacheTable.getCell(
+ static_cast<SCCOL>(nDim), static_cast<SCROW>(nRow), IsRepeatIfEmpty());
+ if (!pCell || pCell->mnType == SC_VALTYPE_EMPTY)
+ continue;
+
+ const String* pString = GetSharedString().getString(pCell->mnStrId);
+ if (!pString)
+ continue;
+
+ rData.aString = *pString;
+ rData.bHasValue = false;
+ if (pCell->mbNumeric)
+ {
+ rData.bHasValue = true;
+ rData.fValue = pCell->mfValue;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+
+
+
diff --git a/sc/source/core/data/dptabres.cxx b/sc/source/core/data/dptabres.cxx
new file mode 100644
index 000000000000..398d4d1c7e01
--- /dev/null
+++ b/sc/source/core/data/dptabres.cxx
@@ -0,0 +1,3677 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dptabres.cxx,v $
+ * $Revision: 1.14 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+
+#include "dptabdat.hxx"
+#include "dptabres.hxx"
+#include "dptabsrc.hxx"
+#include "global.hxx"
+#include "subtotal.hxx"
+#include "globstr.hrc"
+#include "datauno.hxx" // ScDataUnoConversion
+
+#include "document.hxx" // for DumpState only!
+
+#include <math.h>
+#include <float.h> //! Test !!!
+#include <algorithm>
+#include <hash_map>
+
+#include <com/sun/star/sheet/DataResultFlags.hpp>
+#include <com/sun/star/sheet/MemberResultFlags.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
+#include <com/sun/star/sheet/DataPilotFieldShowItemsMode.hpp>
+#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+
+using namespace com::sun::star;
+using ::std::vector;
+using ::std::pair;
+using ::std::hash_map;
+using ::com::sun::star::uno::Sequence;
+
+// -----------------------------------------------------------------------
+
+SV_IMPL_PTRARR( ScDPDataMembers, ScDPDataMemberPtr );
+
+// -----------------------------------------------------------------------
+
+static USHORT nFuncStrIds[12] = // passend zum enum ScSubTotalFunc
+{
+ 0, // SUBTOTAL_FUNC_NONE
+ STR_FUN_TEXT_AVG, // SUBTOTAL_FUNC_AVE
+ STR_FUN_TEXT_COUNT, // SUBTOTAL_FUNC_CNT
+ STR_FUN_TEXT_COUNT, // SUBTOTAL_FUNC_CNT2
+ STR_FUN_TEXT_MAX, // SUBTOTAL_FUNC_MAX
+ STR_FUN_TEXT_MIN, // SUBTOTAL_FUNC_MIN
+ STR_FUN_TEXT_PRODUCT, // SUBTOTAL_FUNC_PROD
+ STR_FUN_TEXT_STDDEV, // SUBTOTAL_FUNC_STD
+ STR_FUN_TEXT_STDDEV, // SUBTOTAL_FUNC_STDP
+ STR_FUN_TEXT_SUM, // SUBTOTAL_FUNC_SUM
+ STR_FUN_TEXT_VAR, // SUBTOTAL_FUNC_VAR
+ STR_FUN_TEXT_VAR // SUBTOTAL_FUNC_VARP
+};
+
+// -----------------------------------------------------------------------
+
+//
+// function objects for sorting of the column and row members:
+//
+
+class ScDPRowMembersOrder
+{
+ ScDPResultDimension& rDimension;
+ long nMeasure;
+ BOOL bAscending;
+
+public:
+ ScDPRowMembersOrder( ScDPResultDimension& rDim, long nM, BOOL bAsc ) :
+ rDimension(rDim),
+ nMeasure(nM),
+ bAscending(bAsc)
+ {}
+ ~ScDPRowMembersOrder() {}
+
+ BOOL operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
+};
+
+class ScDPColMembersOrder
+{
+ ScDPDataDimension& rDimension;
+ long nMeasure;
+ BOOL bAscending;
+
+public:
+ ScDPColMembersOrder( ScDPDataDimension& rDim, long nM, BOOL bAsc ) :
+ rDimension(rDim),
+ nMeasure(nM),
+ bAscending(bAsc)
+ {}
+ ~ScDPColMembersOrder() {}
+
+ BOOL operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
+};
+
+static BOOL lcl_IsLess( const ScDPDataMember* pDataMember1, const ScDPDataMember* pDataMember2, long nMeasure, BOOL bAscending )
+{
+ // members can be NULL if used for rows
+
+ ScDPSubTotalState aEmptyState;
+ const ScDPAggData* pAgg1 = pDataMember1 ? pDataMember1->GetConstAggData( nMeasure, aEmptyState ) : NULL;
+ const ScDPAggData* pAgg2 = pDataMember2 ? pDataMember2->GetConstAggData( nMeasure, aEmptyState ) : NULL;
+
+ BOOL bError1 = pAgg1 && pAgg1->HasError();
+ BOOL bError2 = pAgg2 && pAgg2->HasError();
+ if ( bError1 )
+ {
+ if ( bError2 )
+ return FALSE; // equal
+ else
+ return FALSE; // errors are always sorted at the end
+ }
+ else if ( bError2 )
+ return TRUE; // errors are always sorted at the end
+ else
+ {
+ double fVal1 = ( pAgg1 && pAgg1->HasData() ) ? pAgg1->GetResult() : 0.0; // no data is sorted as 0
+ double fVal2 = ( pAgg2 && pAgg2->HasData() ) ? pAgg2->GetResult() : 0.0;
+
+ // compare values
+ // don't have to check approxEqual, as this is the only sort criterion
+
+ return bAscending ? ( fVal1 < fVal2 ) : ( fVal1 > fVal2 );
+ }
+}
+
+static BOOL lcl_IsEqual( const ScDPDataMember* pDataMember1, const ScDPDataMember* pDataMember2, long nMeasure )
+{
+ // members can be NULL if used for rows
+
+ ScDPSubTotalState aEmptyState;
+ const ScDPAggData* pAgg1 = pDataMember1 ? pDataMember1->GetConstAggData( nMeasure, aEmptyState ) : NULL;
+ const ScDPAggData* pAgg2 = pDataMember2 ? pDataMember2->GetConstAggData( nMeasure, aEmptyState ) : NULL;
+
+ BOOL bError1 = pAgg1 && pAgg1->HasError();
+ BOOL bError2 = pAgg2 && pAgg2->HasError();
+ if ( bError1 )
+ {
+ if ( bError2 )
+ return TRUE; // equal
+ else
+ return FALSE;
+ }
+ else if ( bError2 )
+ return FALSE;
+ else
+ {
+ double fVal1 = ( pAgg1 && pAgg1->HasData() ) ? pAgg1->GetResult() : 0.0; // no data is sorted as 0
+ double fVal2 = ( pAgg2 && pAgg2->HasData() ) ? pAgg2->GetResult() : 0.0;
+
+ // compare values
+ // this is used to find equal data at the end of the AutoShow range, so approxEqual must be used
+
+ return rtl::math::approxEqual( fVal1, fVal2 );
+ }
+}
+
+BOOL ScDPRowMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
+{
+ const ScDPResultMember* pMember1 = rDimension.GetMember(nIndex1);
+ const ScDPResultMember* pMember2 = rDimension.GetMember(nIndex2);
+
+ // GetDataRoot can be NULL if there was no data.
+ // IsVisible == FALSE can happen after AutoShow.
+ const ScDPDataMember* pDataMember1 = pMember1->IsVisible() ? pMember1->GetDataRoot() : NULL;
+ const ScDPDataMember* pDataMember2 = pMember2->IsVisible() ? pMember2->GetDataRoot() : NULL;
+
+ return lcl_IsLess( pDataMember1, pDataMember2, nMeasure, bAscending );
+}
+
+BOOL ScDPColMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
+{
+ ScDPDataMember* pDataMember1 = rDimension.GetMember(nIndex1);
+ ScDPDataMember* pDataMember2 = rDimension.GetMember(nIndex2);
+
+ if ( pDataMember1 && !pDataMember1->IsVisible() ) //! IsColVisible?
+ pDataMember1 = NULL;
+ if ( pDataMember2 && !pDataMember2->IsVisible() )
+ pDataMember2 = NULL;
+
+ return lcl_IsLess( pDataMember1, pDataMember2, nMeasure, bAscending );
+}
+
+// -----------------------------------------------------------------------
+
+ScDPInitState::ScDPInitState() :
+ nCount( 0 )
+{
+ pIndex = new long[SC_DAPI_MAXFIELDS];
+ pData = new ScDPItemData[SC_DAPI_MAXFIELDS];
+}
+
+ScDPInitState::~ScDPInitState()
+{
+ delete[] pIndex;
+ delete[] pData;
+}
+
+void ScDPInitState::AddMember( long nSourceIndex, const ScDPItemData& rName )
+{
+ DBG_ASSERT( nCount < SC_DAPI_MAXFIELDS, "too many InitState members" );
+ if ( nCount < SC_DAPI_MAXFIELDS )
+ {
+ pIndex[nCount] = nSourceIndex;
+ pData[nCount] = rName;
+ ++nCount;
+ }
+}
+
+void ScDPInitState::RemoveMember()
+{
+ DBG_ASSERT( nCount > 0, "RemoveColIndex without index" );
+ if ( nCount > 0 )
+ --nCount;
+}
+
+const ScDPItemData* ScDPInitState::GetNameForIndex( long nIndexValue ) const
+{
+ for (long i=0; i<nCount; i++)
+ if ( pIndex[i] == nIndexValue )
+ return &pData[i];
+
+ return NULL; // not found
+}
+
+// -----------------------------------------------------------------------
+
+void lcl_DumpRow( const String& rType, const String& rName, const ScDPAggData* pAggData,
+ ScDocument* pDoc, ScAddress& rPos )
+{
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+ pDoc->SetString( nCol++, nRow, nTab, rType );
+ pDoc->SetString( nCol++, nRow, nTab, rName );
+ while ( pAggData )
+ {
+ pDoc->SetValue( nCol++, nRow, nTab, pAggData->GetResult() );
+ pAggData = pAggData->GetExistingChild();
+ }
+ rPos.SetRow( nRow + 1 );
+}
+
+void lcl_Indent( ScDocument* pDoc, SCROW nStartRow, const ScAddress& rPos )
+{
+ SCCOL nCol = rPos.Col();
+ SCTAB nTab = rPos.Tab();
+
+ String aString;
+ for (SCROW nRow = nStartRow; nRow < rPos.Row(); nRow++)
+ {
+ pDoc->GetString( nCol, nRow, nTab, aString );
+ if ( aString.Len() )
+ {
+ aString.InsertAscii( " ", 0 );
+ pDoc->SetString( nCol, nRow, nTab, aString );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ScDPRunningTotalState::ScDPRunningTotalState( ScDPResultMember* pColRoot, ScDPResultMember* pRowRoot ) :
+ pColResRoot( pColRoot ),
+ pRowResRoot( pRowRoot ),
+ nColIndexPos( 0 ),
+ nRowIndexPos( 0 )
+{
+ pColVisible = new long[SC_DAPI_MAXFIELDS+1];
+ pColIndexes = new long[SC_DAPI_MAXFIELDS+1];
+ pRowVisible = new long[SC_DAPI_MAXFIELDS+1];
+ pRowIndexes = new long[SC_DAPI_MAXFIELDS+1];
+ pColIndexes[0] = -1;
+ pRowIndexes[0] = -1;
+}
+
+ScDPRunningTotalState::~ScDPRunningTotalState()
+{
+ delete[] pColVisible;
+ delete[] pColIndexes;
+ delete[] pRowVisible;
+ delete[] pRowIndexes;
+}
+
+void ScDPRunningTotalState::AddColIndex( long nVisible, long nSorted )
+{
+ DBG_ASSERT( nColIndexPos < SC_DAPI_MAXFIELDS, "too many column indexes" );
+ if ( nColIndexPos < SC_DAPI_MAXFIELDS )
+ {
+ pColVisible[nColIndexPos] = nVisible;
+ pColIndexes[nColIndexPos] = nSorted;
+ pColVisible[nColIndexPos+1] = -1;
+ pColIndexes[nColIndexPos+1] = -1;
+ ++nColIndexPos;
+ }
+}
+
+void ScDPRunningTotalState::AddRowIndex( long nVisible, long nSorted )
+{
+ DBG_ASSERT( nRowIndexPos < SC_DAPI_MAXFIELDS, "too many row indexes" );
+ if ( nRowIndexPos < SC_DAPI_MAXFIELDS )
+ {
+ pRowVisible[nRowIndexPos] = nVisible;
+ pRowIndexes[nRowIndexPos] = nSorted;
+ pRowVisible[nRowIndexPos+1] = -1;
+ pRowIndexes[nRowIndexPos+1] = -1;
+ ++nRowIndexPos;
+ }
+}
+
+void ScDPRunningTotalState::RemoveColIndex()
+{
+ DBG_ASSERT( nColIndexPos > 0, "RemoveColIndex without index" );
+ if ( nColIndexPos > 0 )
+ {
+ --nColIndexPos;
+ pColVisible[nColIndexPos] = -1;
+ pColIndexes[nColIndexPos] = -1;
+ }
+}
+
+void ScDPRunningTotalState::RemoveRowIndex()
+{
+ DBG_ASSERT( nRowIndexPos > 0, "RemoveRowIndex without index" );
+ if ( nRowIndexPos > 0 )
+ {
+ --nRowIndexPos;
+ pRowVisible[nRowIndexPos] = -1;
+ pRowIndexes[nRowIndexPos] = -1;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ScDPRelativePos::ScDPRelativePos( long nBase, long nDir ) :
+ nBasePos( nBase ),
+ nDirection( nDir )
+{
+}
+
+// -----------------------------------------------------------------------
+
+void ScDPAggData::Update( const ScDPValueData& rNext, ScSubTotalFunc eFunc, const ScDPSubTotalState& rSubState )
+{
+ if (nCount<0) // error?
+ return; // nothing more...
+
+ if ( rNext.nType == SC_VALTYPE_EMPTY )
+ return;
+
+ if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE && rSubState.eRowForce != SUBTOTAL_FUNC_NONE &&
+ rSubState.eColForce != rSubState.eRowForce )
+ return;
+ if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eColForce;
+ if ( rSubState.eRowForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eRowForce;
+
+ if ( eFunc == SUBTOTAL_FUNC_NONE )
+ return;
+
+ if ( eFunc != SUBTOTAL_FUNC_CNT2 ) // CNT2 counts everything, incl. strings and errors
+ {
+ if ( rNext.nType == SC_VALTYPE_ERROR )
+ {
+ nCount = -1; // -1 for error (not for CNT2)
+ return;
+ }
+ if ( rNext.nType == SC_VALTYPE_STRING )
+ return; // ignore
+ }
+
+ ++nCount; // for all functions
+
+ switch (eFunc)
+ {
+ case SUBTOTAL_FUNC_SUM:
+ case SUBTOTAL_FUNC_AVE:
+ if ( !SubTotal::SafePlus( fVal, rNext.fValue ) )
+ nCount = -1; // -1 for error
+ break;
+ case SUBTOTAL_FUNC_PROD:
+ if ( nCount == 1 ) // copy first value (fVal is initialized to 0)
+ fVal = rNext.fValue;
+ else if ( !SubTotal::SafeMult( fVal, rNext.fValue ) )
+ nCount = -1; // -1 for error
+ break;
+ case SUBTOTAL_FUNC_CNT:
+ case SUBTOTAL_FUNC_CNT2:
+ // nothing more than incrementing nCount
+ break;
+ case SUBTOTAL_FUNC_MAX:
+ if ( nCount == 1 || rNext.fValue > fVal )
+ fVal = rNext.fValue;
+ break;
+ case SUBTOTAL_FUNC_MIN:
+ if ( nCount == 1 || rNext.fValue < fVal )
+ fVal = rNext.fValue;
+ break;
+ case SUBTOTAL_FUNC_STD:
+ case SUBTOTAL_FUNC_STDP:
+ case SUBTOTAL_FUNC_VAR:
+ case SUBTOTAL_FUNC_VARP:
+ {
+ // fAux is used to sum up squares
+ if ( !SubTotal::SafePlus( fVal, rNext.fValue ) )
+ nCount = -1; // -1 for error
+ double fAdd = rNext.fValue;
+ if ( !SubTotal::SafeMult( fAdd, rNext.fValue ) ||
+ !SubTotal::SafePlus( fAux, fAdd ) )
+ nCount = -1; // -1 for error
+ }
+ break;
+ default:
+ DBG_ERROR("invalid function");
+ }
+}
+
+void ScDPAggData::Calculate( ScSubTotalFunc eFunc, const ScDPSubTotalState& rSubState )
+{
+ // calculate the original result
+ // (without reference value, used as the basis for reference value calculation)
+
+ // called several times at the cross-section of several subtotals - don't calculate twice then
+ if ( IsCalculated() )
+ return;
+
+ if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eColForce;
+ if ( rSubState.eRowForce != SUBTOTAL_FUNC_NONE ) eFunc = rSubState.eRowForce;
+
+ if ( eFunc == SUBTOTAL_FUNC_NONE ) // this happens when there is no data dimension
+ {
+ nCount = SC_DPAGG_RESULT_EMPTY; // make sure there's a valid state for HasData etc.
+ return;
+ }
+
+ // check the error conditions for the selected function
+
+ BOOL bError = FALSE;
+ switch (eFunc)
+ {
+ case SUBTOTAL_FUNC_SUM:
+ case SUBTOTAL_FUNC_PROD:
+ case SUBTOTAL_FUNC_CNT:
+ case SUBTOTAL_FUNC_CNT2:
+ bError = ( nCount < 0 ); // only real errors
+ break;
+
+ case SUBTOTAL_FUNC_AVE:
+ case SUBTOTAL_FUNC_MAX:
+ case SUBTOTAL_FUNC_MIN:
+ case SUBTOTAL_FUNC_STDP:
+ case SUBTOTAL_FUNC_VARP:
+ bError = ( nCount <= 0 ); // no data is an error
+ break;
+
+ case SUBTOTAL_FUNC_STD:
+ case SUBTOTAL_FUNC_VAR:
+ bError = ( nCount < 2 ); // need at least 2 values
+ break;
+
+ default:
+ DBG_ERROR("invalid function");
+ }
+
+ // calculate the selected function
+
+ double fResult = 0.0;
+ if ( !bError )
+ {
+ switch (eFunc)
+ {
+ case SUBTOTAL_FUNC_MAX:
+ case SUBTOTAL_FUNC_MIN:
+ case SUBTOTAL_FUNC_SUM:
+ case SUBTOTAL_FUNC_PROD:
+ // different error conditions are handled above
+ fResult = fVal;
+ break;
+
+ case SUBTOTAL_FUNC_CNT:
+ case SUBTOTAL_FUNC_CNT2:
+ fResult = nCount;
+ break;
+
+ case SUBTOTAL_FUNC_AVE:
+ if ( nCount > 0 )
+ fResult = fVal / (double) nCount;
+ break;
+
+ //! use safe mul for fVal * fVal
+
+ case SUBTOTAL_FUNC_STD:
+ if ( nCount >= 2 )
+ fResult = sqrt((fAux - fVal*fVal/(double)(nCount)) / (double)(nCount-1));
+ break;
+ case SUBTOTAL_FUNC_VAR:
+ if ( nCount >= 2 )
+ fResult = (fAux - fVal*fVal/(double)(nCount)) / (double)(nCount-1);
+ break;
+ case SUBTOTAL_FUNC_STDP:
+ if ( nCount > 0 )
+ fResult = sqrt((fAux - fVal*fVal/(double)(nCount)) / (double)nCount);
+ break;
+ case SUBTOTAL_FUNC_VARP:
+ if ( nCount > 0 )
+ fResult = (fAux - fVal*fVal/(double)(nCount)) / (double)nCount;
+ break;
+ default:
+ DBG_ERROR("invalid function");
+ }
+ }
+
+ BOOL bEmpty = ( nCount == 0 ); // no data
+
+ // store the result
+ // Empty is checked first, so empty results are shown empty even for "average" etc.
+ // If these results should be treated as errors in reference value calculations,
+ // a separate state value (EMPTY_ERROR) is needed.
+ // Now, for compatibility, empty "average" results are counted as 0.
+
+ if ( bEmpty )
+ nCount = SC_DPAGG_RESULT_EMPTY;
+ else if ( bError )
+ nCount = SC_DPAGG_RESULT_ERROR;
+ else
+ nCount = SC_DPAGG_RESULT_VALID;
+
+ if ( bEmpty || bError )
+ fResult = 0.0; // default, in case the state is later modified
+
+// fprintf(stdout, "ScDPAggData::Calculate: result = %g\n", fResult);fflush(stdout);
+ fVal = fResult; // used directly from now on
+ fAux = 0.0; // used for running total or original result of reference value
+}
+
+BOOL ScDPAggData::IsCalculated() const
+{
+ return ( nCount <= SC_DPAGG_RESULT_EMPTY );
+}
+
+double ScDPAggData::GetResult() const
+{
+ DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );
+
+ return fVal; // use calculated value
+}
+
+BOOL ScDPAggData::HasError() const
+{
+ DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );
+
+ return ( nCount == SC_DPAGG_RESULT_ERROR );
+}
+
+BOOL ScDPAggData::HasData() const
+{
+ DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );
+
+ return ( nCount != SC_DPAGG_RESULT_EMPTY ); // values or error
+}
+
+void ScDPAggData::SetResult( double fNew )
+{
+ DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );
+
+ fVal = fNew; // don't reset error flag
+}
+
+void ScDPAggData::SetError()
+{
+ DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );
+
+ nCount = SC_DPAGG_RESULT_ERROR;
+}
+
+void ScDPAggData::SetEmpty( BOOL bSet )
+{
+ DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );
+
+ if ( bSet )
+ nCount = SC_DPAGG_RESULT_EMPTY;
+ else
+ nCount = SC_DPAGG_RESULT_VALID;
+}
+
+double ScDPAggData::GetAuxiliary() const
+{
+ // after Calculate, fAux is used as auxiliary value for running totals and reference values
+ DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );
+
+ return fAux;
+}
+
+void ScDPAggData::SetAuxiliary( double fNew )
+{
+ // after Calculate, fAux is used as auxiliary value for running totals and reference values
+ DBG_ASSERT( IsCalculated(), "ScDPAggData not calculated" );
+
+ fAux = fNew;
+}
+
+ScDPAggData* ScDPAggData::GetChild()
+{
+ if (!pChild)
+ pChild = new ScDPAggData;
+ return pChild;
+}
+
+void ScDPAggData::Reset()
+{
+ fVal = 0.0;
+ fAux = 0.0;
+ nCount = SC_DPAGG_EMPTY;
+ delete pChild;
+ pChild = NULL;
+}
+
+// -----------------------------------------------------------------------
+
+ScDPRowTotals::ScDPRowTotals() :
+ bIsInColRoot( FALSE )
+{
+}
+
+ScDPRowTotals::~ScDPRowTotals()
+{
+}
+
+ScDPAggData* lcl_GetChildTotal( ScDPAggData* pFirst, long nMeasure )
+{
+ DBG_ASSERT( nMeasure >= 0, "GetColTotal: no measure" );
+
+ ScDPAggData* pAgg = pFirst;
+ long nSkip = nMeasure;
+
+ // subtotal settings are ignored - colum/row totals exist once per measure
+
+ for ( long nPos=0; nPos<nSkip; nPos++ )
+ pAgg = pAgg->GetChild(); // column total is constructed empty - children need to be created
+
+ if ( !pAgg->IsCalculated() )
+ {
+ // for first use, simulate an empty calculation
+ ScDPSubTotalState aEmptyState;
+ pAgg->Calculate( SUBTOTAL_FUNC_SUM, aEmptyState );
+ }
+
+ return pAgg;
+}
+
+ScDPAggData* ScDPRowTotals::GetRowTotal( long nMeasure )
+{
+ return lcl_GetChildTotal( &aRowTotal, nMeasure );
+}
+
+ScDPAggData* ScDPRowTotals::GetGrandTotal( long nMeasure )
+{
+ return lcl_GetChildTotal( &aGrandTotal, nMeasure );
+}
+
+// -----------------------------------------------------------------------
+
+static ScSubTotalFunc lcl_GetForceFunc( const ScDPLevel* pLevel, long nFuncNo )
+{
+ ScSubTotalFunc eRet = SUBTOTAL_FUNC_NONE;
+ if ( pLevel )
+ {
+ //! direct access via ScDPLevel
+
+ uno::Sequence<sheet::GeneralFunction> aSeq = pLevel->getSubTotals();
+ long nSequence = aSeq.getLength();
+ if ( nSequence && aSeq[0] != sheet::GeneralFunction_AUTO )
+ {
+ // For manual subtotals, "automatic" is added as first function.
+ // ScDPResultMember::GetSubTotalCount adds to the count, here NONE has to be
+ // returned as the first function then.
+
+ --nFuncNo; // keep NONE for first (check below), move the other entries
+ }
+
+ if ( nFuncNo >= 0 && nFuncNo < nSequence )
+ {
+ sheet::GeneralFunction eUser = aSeq.getConstArray()[nFuncNo];
+ if (eUser != sheet::GeneralFunction_AUTO)
+ eRet = ScDataUnoConversion::GeneralToSubTotal( eUser );
+ }
+ }
+ return eRet;
+}
+
+// -----------------------------------------------------------------------
+
+ScDPResultData::ScDPResultData( ScDPSource* pSrc ) : //! Ref
+ pSource( pSrc ),
+ nMeasCount( 0 ),
+ pMeasFuncs( NULL ),
+ pMeasRefs( NULL ),
+ pMeasRefOrient( NULL ),
+ pMeasNames( NULL ),
+ bLateInit( FALSE ),
+ bDataAtCol( FALSE ),
+ bDataAtRow( FALSE )
+{
+}
+
+ScDPResultData::~ScDPResultData()
+{
+ delete[] pMeasFuncs;
+ delete[] pMeasRefs;
+ delete[] pMeasRefOrient;
+ delete[] pMeasNames;
+}
+
+void ScDPResultData::SetMeasureData( long nCount, const ScSubTotalFunc* pFunctions,
+ const sheet::DataPilotFieldReference* pRefs, const USHORT* pRefOrient,
+ const String* pNames )
+{
+ delete[] pMeasFuncs;
+ delete[] pMeasRefs;
+ delete[] pMeasRefOrient;
+ delete[] pMeasNames;
+ if ( nCount )
+ {
+ nMeasCount = nCount;
+ pMeasFuncs = new ScSubTotalFunc[nCount];
+ pMeasRefs = new sheet::DataPilotFieldReference[nCount];
+ pMeasRefOrient = new USHORT[nCount];
+ pMeasNames = new String[nCount];
+ for (long i=0; i<nCount; i++)
+ {
+ pMeasFuncs[i] = pFunctions[i];
+ pMeasRefs[i] = pRefs[i];
+ pMeasRefOrient[i] = pRefOrient[i];
+ pMeasNames[i] = pNames[i];
+ }
+ }
+ else
+ {
+ // use one dummy measure
+ nMeasCount = 1;
+ pMeasFuncs = new ScSubTotalFunc[1];
+ pMeasFuncs[0] = SUBTOTAL_FUNC_NONE;
+ pMeasRefs = new sheet::DataPilotFieldReference[1]; // default ctor is ok
+ pMeasRefOrient = new USHORT[1];
+ pMeasRefOrient[0] = sheet::DataPilotFieldOrientation_HIDDEN;
+ pMeasNames = new String[1];
+ pMeasNames[0] = ScGlobal::GetRscString( STR_EMPTYDATA );
+ }
+}
+
+void ScDPResultData::SetDataLayoutOrientation( USHORT nOrient )
+{
+ bDataAtCol = ( nOrient == sheet::DataPilotFieldOrientation_COLUMN );
+ bDataAtRow = ( nOrient == sheet::DataPilotFieldOrientation_ROW );
+}
+
+void ScDPResultData::SetLateInit( BOOL bSet )
+{
+ bLateInit = bSet;
+}
+
+long ScDPResultData::GetColStartMeasure() const
+{
+ if ( nMeasCount == 1 ) return 0;
+ return bDataAtCol ? SC_DPMEASURE_ALL : SC_DPMEASURE_ANY;
+}
+
+long ScDPResultData::GetRowStartMeasure() const
+{
+ if ( nMeasCount == 1 ) return 0;
+ return bDataAtRow ? SC_DPMEASURE_ALL : SC_DPMEASURE_ANY;
+}
+
+ScSubTotalFunc ScDPResultData::GetMeasureFunction(long nMeasure) const
+{
+ DBG_ASSERT( pMeasFuncs && nMeasure < nMeasCount, "bumm" );
+ return pMeasFuncs[nMeasure];
+}
+
+const sheet::DataPilotFieldReference& ScDPResultData::GetMeasureRefVal(long nMeasure) const
+{
+ DBG_ASSERT( pMeasRefs && nMeasure < nMeasCount, "bumm" );
+ return pMeasRefs[nMeasure];
+}
+
+USHORT ScDPResultData::GetMeasureRefOrient(long nMeasure) const
+{
+ DBG_ASSERT( pMeasRefOrient && nMeasure < nMeasCount, "bumm" );
+ return pMeasRefOrient[nMeasure];
+}
+
+String ScDPResultData::GetMeasureString(long nMeasure, BOOL bForce, ScSubTotalFunc eForceFunc) const
+{
+ // with bForce==TRUE, return function instead of "result" for single measure
+ // with eForceFunc != SUBTOTAL_FUNC_NONE, always use eForceFunc
+
+ if ( nMeasure < 0 || ( nMeasCount == 1 && !bForce && eForceFunc == SUBTOTAL_FUNC_NONE ) )
+ {
+ // for user-specified subtotal function with all measures,
+ // display only function name
+ if ( eForceFunc != SUBTOTAL_FUNC_NONE )
+ return ScGlobal::GetRscString(nFuncStrIds[eForceFunc]);
+
+ return ScGlobal::GetRscString(STR_TABLE_ERGEBNIS);
+ }
+ else
+ {
+ DBG_ASSERT( pMeasNames && nMeasure < nMeasCount, "bumm" );
+
+ String aRet;
+ ScSubTotalFunc eFunc = ( eForceFunc == SUBTOTAL_FUNC_NONE ) ?
+ GetMeasureFunction(nMeasure) : eForceFunc;
+ USHORT nId = nFuncStrIds[eFunc];
+ if (nId)
+ {
+ aRet += ScGlobal::GetRscString(nId); // function name
+ aRet.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " - " ));
+ }
+ aRet += pMeasNames[nMeasure]; // field name
+
+ return aRet;
+ }
+}
+
+String ScDPResultData::GetMeasureDimensionName(long nMeasure) const
+{
+ if ( nMeasure < 0 )
+ {
+ DBG_ERROR("GetMeasureDimensionName: negative");
+ return String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("***"));
+ }
+
+ return pSource->GetDataDimName( nMeasure );
+}
+
+BOOL ScDPResultData::IsBaseForGroup( long nDim ) const
+{
+ return pSource->GetData()->IsBaseForGroup( nDim );
+}
+
+long ScDPResultData::GetGroupBase( long nGroupDim ) const
+{
+ return pSource->GetData()->GetGroupBase( nGroupDim );
+}
+
+BOOL ScDPResultData::IsNumOrDateGroup( long nDim ) const
+{
+ return pSource->GetData()->IsNumOrDateGroup( nDim );
+}
+
+BOOL ScDPResultData::IsInGroup( const ScDPItemData& rGroupData, long nGroupIndex,
+ const ScDPItemData& rBaseData, long nBaseIndex ) const
+{
+ return pSource->GetData()->IsInGroup( rGroupData, nGroupIndex, rBaseData, nBaseIndex );
+}
+
+BOOL ScDPResultData::HasCommonElement( const ScDPItemData& rFirstData, long nFirstIndex,
+ const ScDPItemData& rSecondData, long nSecondIndex ) const
+{
+ return pSource->GetData()->HasCommonElement( rFirstData, nFirstIndex, rSecondData, nSecondIndex );
+}
+
+// -----------------------------------------------------------------------
+
+
+ScDPResultMember::ScDPResultMember( const ScDPResultData* pData, const ScDPDimension* pDim,
+ const ScDPLevel* pLev, const ScDPMember* pDesc,
+ BOOL bForceSub ) :
+ pResultData( pData ),
+ pParentDim( pDim ),
+ pParentLevel( pLev ),
+ pMemberDesc( pDesc ),
+ pChildDimension( NULL ),
+ pDataRoot( NULL ),
+ bHasElements( FALSE ),
+ bForceSubTotal( bForceSub ),
+ bHasHiddenDetails( FALSE ),
+ bInitialized( FALSE ),
+ bAutoHidden( FALSE )
+{
+ // pParentLevel/pMemberDesc is 0 for root members
+}
+
+ScDPResultMember::~ScDPResultMember()
+{
+ delete pChildDimension;
+ delete pDataRoot;
+}
+
+String ScDPResultMember::GetName() const
+{
+ if (pMemberDesc)
+ return pMemberDesc->GetNameStr();
+ else
+ return ScGlobal::GetRscString(STR_PIVOT_TOTAL); // root member
+}
+
+void ScDPResultMember::FillItemData( ScDPItemData& rData ) const
+{
+ if (pMemberDesc)
+ pMemberDesc->FillItemData( rData );
+ else
+ rData.SetString( ScGlobal::GetRscString(STR_PIVOT_TOTAL) ); // root member
+}
+
+BOOL ScDPResultMember::IsNamedItem( const ScDPItemData& r ) const
+{
+ //! store ScDPMember pointer instead of ScDPMember ???
+
+ if (pMemberDesc)
+ return ((ScDPMember*)pMemberDesc)->IsNamedItem( r );
+ return FALSE;
+}
+
+bool ScDPResultMember::IsValidEntry( const vector<ScDPItemData>& aMembers ) const
+{
+ if ( !IsValid() )
+ return false;
+
+ const ScDPResultDimension* pChildDim = GetChildDimension();
+ if (pChildDim)
+ {
+ if (aMembers.size() < 2)
+ return false;
+
+ vector<ScDPItemData>::const_iterator itr = aMembers.begin();
+ vector<ScDPItemData> aChildMembers(++itr, aMembers.end());
+ return pChildDim->IsValidEntry(aChildMembers);
+ }
+ else
+ return true;
+}
+
+void ScDPResultMember::InitFrom( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev,
+ size_t nPos, ScDPInitState& rInitState )
+{
+ // with LateInit, initialize only those members that have data
+ if ( pResultData->IsLateInit() )
+ return;
+
+ bInitialized = TRUE;
+
+ if (nPos >= ppDim.size())
+ return;
+
+ // skip child dimension if details are not shown
+ if ( pMemberDesc && !pMemberDesc->getShowDetails() )
+ {
+ bHasHiddenDetails = TRUE; // only if there is a next dimension
+ return;
+ }
+
+ pChildDimension = new ScDPResultDimension( pResultData );
+ pChildDimension->InitFrom( ppDim, ppLev, nPos, rInitState );
+}
+
+void ScDPResultMember::LateInitFrom( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev,
+ const vector<ScDPItemData>& pItemData, size_t nPos,
+ ScDPInitState& rInitState )
+{
+ // without LateInit, everything has already been initialized
+ if ( !pResultData->IsLateInit() )
+ return;
+
+ bInitialized = TRUE;
+
+ if (nPos >= ppDim.size())
+ // No next dimension. Bail out.
+ return;
+
+ // skip child dimension if details are not shown
+ if ( pMemberDesc && !pMemberDesc->getShowDetails() )
+ {
+ bHasHiddenDetails = TRUE; // only if there is a next dimension
+ return;
+ }
+
+ // LateInitFrom is called several times...
+ if ( !pChildDimension )
+ pChildDimension = new ScDPResultDimension( pResultData );
+
+ pChildDimension->LateInitFrom( ppDim, ppLev, pItemData, nPos, rInitState );
+}
+
+BOOL ScDPResultMember::IsSubTotalInTitle(long nMeasure) const
+{
+ BOOL bRet = FALSE;
+ if ( pChildDimension && pParentLevel &&
+ pParentLevel->IsOutlineLayout() && pParentLevel->IsSubtotalsAtTop() )
+ {
+ long nUserSubStart;
+ long nSubTotals = GetSubTotalCount( &nUserSubStart );
+ nSubTotals -= nUserSubStart; // visible count
+ if ( nSubTotals )
+ {
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ nSubTotals *= pResultData->GetMeasureCount(); // number of subtotals that will be inserted
+
+ // only a single subtotal row will be shown in the outline title row
+ if ( nSubTotals == 1 )
+ bRet = TRUE;
+ }
+ }
+ return bRet;
+}
+
+long ScDPResultMember::GetSize(long nMeasure) const
+{
+ if ( !IsVisible() )
+ return 0;
+
+ long nExtraSpace = 0;
+ if ( pParentLevel && pParentLevel->IsAddEmpty() )
+ ++nExtraSpace;
+
+ if ( pChildDimension )
+ {
+ // outline layout takes up an extra row for the title only if subtotals aren't shown in that row
+ if ( pParentLevel && pParentLevel->IsOutlineLayout() && !IsSubTotalInTitle( nMeasure ) )
+ ++nExtraSpace;
+
+ long nSize = pChildDimension->GetSize(nMeasure);
+ long nUserSubStart;
+ long nUserSubCount = GetSubTotalCount( &nUserSubStart );
+ nUserSubCount -= nUserSubStart; // for output size, use visible count
+ if ( nUserSubCount )
+ {
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ nSize += pResultData->GetMeasureCount() * nUserSubCount;
+ else
+ nSize += nUserSubCount;
+ }
+ return nSize + nExtraSpace;
+ }
+ else
+ {
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ return pResultData->GetMeasureCount() + nExtraSpace;
+ else
+ return 1 + nExtraSpace;
+ }
+}
+
+BOOL ScDPResultMember::IsVisible() const
+{
+ // not initialized -> shouldn't be there at all
+ // (allocated only to preserve ordering)
+
+ return ( bHasElements || ( pParentLevel && pParentLevel->getShowEmpty() ) ) && IsValid() && bInitialized;
+}
+
+BOOL ScDPResultMember::IsValid() const
+{
+ // non-Valid members are left out of calculation
+
+ // was member set no invisible at the DataPilotSource?
+ if ( pMemberDesc && !pMemberDesc->getIsVisible() )
+ return FALSE;
+
+ if ( bAutoHidden )
+ return FALSE;
+
+ return TRUE;
+}
+
+BOOL ScDPResultMember::HasHiddenDetails() const
+{
+ // bHasHiddenDetails is set only if the "show details" flag is off,
+ // and there was a child dimension to skip
+
+ return bHasHiddenDetails;
+}
+
+long ScDPResultMember::GetSubTotalCount( long* pUserSubStart ) const
+{
+ if ( pUserSubStart )
+ *pUserSubStart = 0; // default
+
+ if ( bForceSubTotal ) // set if needed for root members
+ return 1; // grand total is always "automatic"
+ else if ( pParentLevel )
+ {
+ //! direct access via ScDPLevel
+
+ uno::Sequence<sheet::GeneralFunction> aSeq = pParentLevel->getSubTotals();
+ long nSequence = aSeq.getLength();
+ if ( nSequence && aSeq[0] != sheet::GeneralFunction_AUTO )
+ {
+ // For manual subtotals, always add "automatic" as first function
+ // (used for calculation, but not for display, needed for sorting, see lcl_GetForceFunc)
+
+ ++nSequence;
+ if ( pUserSubStart )
+ *pUserSubStart = 1; // visible subtotals start at 1
+ }
+ return nSequence;
+ }
+ else
+ return 0;
+}
+
+void ScDPResultMember::ProcessData( const vector<ScDPItemData>& aChildMembers, const ScDPResultDimension* pDataDim,
+ const vector<ScDPItemData>& aDataMembers, const vector<ScDPValueData>& aValues )
+{
+ SetHasElements();
+
+ if (pChildDimension)
+ pChildDimension->ProcessData( aChildMembers, pDataDim, aDataMembers, aValues );
+
+ if ( !pDataRoot )
+ {
+ pDataRoot = new ScDPDataMember( pResultData, NULL );
+ if ( pDataDim )
+ pDataRoot->InitFrom( pDataDim ); // recursive
+ }
+
+ ScDPSubTotalState aSubState; // initial state
+
+ long nUserSubCount = GetSubTotalCount();
+
+ // Calculate at least automatic if no subtotals are selected,
+ // show only own values if there's no child dimension (innermost).
+ if ( !nUserSubCount || !pChildDimension )
+ nUserSubCount = 1;
+
+ for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
+ {
+ // #i68338# if nUserSubCount is 1 (automatic only), don't set nRowSubTotalFunc
+ if ( pChildDimension && nUserSubCount > 1 )
+ {
+ aSubState.nRowSubTotalFunc = nUserPos;
+ aSubState.eRowForce = lcl_GetForceFunc( pParentLevel, nUserPos );
+ }
+
+ pDataRoot->ProcessData( aDataMembers, aValues, aSubState );
+ }
+}
+
+void ScDPResultMember::FillMemberResults( uno::Sequence<sheet::MemberResult>* pSequences,
+ long& rPos, long nMeasure, BOOL bRoot,
+ const String* pMemberName,
+ const String* pMemberCaption )
+{
+ // IsVisible() test is in ScDPResultDimension::FillMemberResults
+ // (not on data layout dimension)
+
+ long nSize = GetSize(nMeasure);
+ sheet::MemberResult* pArray = pSequences->getArray();
+ DBG_ASSERT( rPos+nSize <= pSequences->getLength(), "bumm" );
+
+ BOOL bIsNumeric = FALSE;
+ String aName;
+ if ( pMemberName ) // if pMemberName != NULL, use instead of real member name
+ aName = *pMemberName;
+ else
+ {
+ ScDPItemData aItemData;
+ FillItemData( aItemData );
+ aName = aItemData.aString;
+ bIsNumeric = aItemData.bHasValue;
+ }
+
+ if ( bIsNumeric && pParentDim && pResultData->IsNumOrDateGroup( pParentDim->GetDimension() ) )
+ {
+ // Numeric group dimensions use numeric entries for proper sorting,
+ // but the group titles must be output as text.
+ bIsNumeric = FALSE;
+ }
+
+ String aCaption = aName;
+ if ( pMemberCaption ) // use pMemberCaption if != NULL
+ aCaption = *pMemberCaption;
+ if (!aCaption.Len())
+ aCaption = ScGlobal::GetRscString(STR_EMPTYDATA);
+
+ if ( !bIsNumeric )
+ {
+ // add a "'" character so a string isn't parsed as value in the output cell
+ //! have a separate bit in Flags (MemberResultFlags) instead?
+ aCaption.Insert( (sal_Unicode) '\'', 0 );
+ }
+
+ if ( nSize && !bRoot ) // root is overwritten by first dimension
+ {
+ pArray[rPos].Name = rtl::OUString(aName);
+ pArray[rPos].Caption = rtl::OUString(aCaption);
+ pArray[rPos].Flags |= sheet::MemberResultFlags::HASMEMBER;
+
+ // set "continue" flag (removed for subtotals later)
+ for (long i=1; i<nSize; i++)
+ pArray[rPos+i].Flags |= sheet::MemberResultFlags::CONTINUE;
+ }
+
+ long nExtraSpace = 0;
+ if ( pParentLevel && pParentLevel->IsAddEmpty() )
+ ++nExtraSpace;
+
+ BOOL bTitleLine = FALSE;
+ if ( pParentLevel && pParentLevel->IsOutlineLayout() )
+ bTitleLine = TRUE;
+
+ // if the subtotals are shown at the top (title row) in outline layout,
+ // no extra row for the subtotals is needed
+ BOOL bSubTotalInTitle = IsSubTotalInTitle( nMeasure );
+
+ BOOL bHasChild = ( pChildDimension != NULL );
+ if (bHasChild)
+ {
+ if ( bTitleLine ) // in tabular layout the title is on a separate row
+ ++rPos; // -> fill child dimension one row below
+
+ if (bRoot) // same sequence for root member
+ pChildDimension->FillMemberResults( pSequences, rPos, nMeasure );
+ else
+ pChildDimension->FillMemberResults( pSequences + 1, rPos, nMeasure );
+
+ if ( bTitleLine ) // title row is included in GetSize, so the following
+ --rPos; // positions are calculated with the normal values
+ }
+
+ rPos += nSize;
+
+ long nUserSubStart;
+ long nUserSubCount = GetSubTotalCount(&nUserSubStart);
+ if ( nUserSubCount && pChildDimension && !bSubTotalInTitle )
+ {
+ long nMemberMeasure = nMeasure;
+ long nSubSize = pResultData->GetCountForMeasure(nMeasure);
+
+ rPos -= nSubSize * (nUserSubCount - nUserSubStart); // GetSize includes space for SubTotal
+ rPos -= nExtraSpace; // GetSize includes the empty line
+
+ for (long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
+ {
+ for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
+ {
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ nMemberMeasure = nSubCount;
+
+ ScSubTotalFunc eForce = SUBTOTAL_FUNC_NONE;
+ if (bHasChild)
+ eForce = lcl_GetForceFunc( pParentLevel, nUserPos );
+
+ String aSubStr = aName; //! caption?
+ aSubStr += ' ';
+ aSubStr += pResultData->GetMeasureString(nMemberMeasure, FALSE, eForce);
+
+ pArray[rPos].Name = rtl::OUString(aName);
+ pArray[rPos].Caption = rtl::OUString(aSubStr);
+ pArray[rPos].Flags = ( pArray[rPos].Flags |
+ ( sheet::MemberResultFlags::HASMEMBER | sheet::MemberResultFlags::SUBTOTAL) ) &
+ ~sheet::MemberResultFlags::CONTINUE;
+
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ {
+ // data layout dimension is (direct/indirect) child of this.
+ // data layout dimension must have name for all entries.
+
+ uno::Sequence<sheet::MemberResult>* pLayoutSeq = pSequences;
+ if (!bRoot)
+ ++pLayoutSeq;
+ ScDPResultDimension* pLayoutDim = pChildDimension;
+ while ( pLayoutDim && !pLayoutDim->IsDataLayout() )
+ {
+ pLayoutDim = pLayoutDim->GetFirstChildDimension();
+ ++pLayoutSeq;
+ }
+ if ( pLayoutDim )
+ {
+ sheet::MemberResult* pLayoutArray = pLayoutSeq->getArray();
+ String aDataName = pResultData->GetMeasureDimensionName(nMemberMeasure);
+ pLayoutArray[rPos].Name = rtl::OUString(aDataName);
+ }
+ }
+
+ rPos += 1;
+ }
+ }
+
+ rPos += nExtraSpace; // add again (subtracted above)
+ }
+}
+
+void ScDPResultMember::FillDataResults( const ScDPResultMember* pRefMember,
+ uno::Sequence< uno::Sequence<sheet::DataResult> >& rSequence,
+ long& rRow, long nMeasure ) const
+{
+ // IsVisible() test is in ScDPResultDimension::FillDataResults
+ // (not on data layout dimension)
+
+ long nStartRow = rRow;
+
+ long nExtraSpace = 0;
+ if ( pParentLevel && pParentLevel->IsAddEmpty() )
+ ++nExtraSpace;
+
+ BOOL bTitleLine = FALSE;
+ if ( pParentLevel && pParentLevel->IsOutlineLayout() )
+ bTitleLine = TRUE;
+
+ BOOL bSubTotalInTitle = IsSubTotalInTitle( nMeasure );
+
+ BOOL bHasChild = ( pChildDimension != NULL );
+ if (bHasChild)
+ {
+ if ( bTitleLine ) // in tabular layout the title is on a separate row
+ ++rRow; // -> fill child dimension one row below
+
+ pChildDimension->FillDataResults( pRefMember, rSequence, rRow, nMeasure ); // doesn't modify rRow
+ rRow += (USHORT) GetSize( nMeasure );
+
+ if ( bTitleLine ) // title row is included in GetSize, so the following
+ --rRow; // positions are calculated with the normal values
+ }
+
+ long nUserSubStart;
+ long nUserSubCount = GetSubTotalCount(&nUserSubStart);
+ if ( nUserSubCount || !bHasChild )
+ {
+ // Calculate at least automatic if no subtotals are selected,
+ // show only own values if there's no child dimension (innermost).
+ if ( !nUserSubCount || !bHasChild )
+ {
+ nUserSubCount = 1;
+ nUserSubStart = 0;
+ }
+
+ long nMemberMeasure = nMeasure;
+ long nSubSize = pResultData->GetCountForMeasure(nMeasure);
+ if (bHasChild)
+ {
+ rRow -= nSubSize * ( nUserSubCount - nUserSubStart ); // GetSize includes space for SubTotal
+ rRow -= nExtraSpace; // GetSize includes the empty line
+ }
+
+ long nMoveSubTotal = 0;
+ if ( bSubTotalInTitle )
+ {
+ nMoveSubTotal = rRow - nStartRow; // force to first (title) row
+ rRow = nStartRow;
+ }
+
+ if ( pDataRoot )
+ {
+ ScDPSubTotalState aSubState; // initial state
+
+ for (long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
+ {
+ if ( bHasChild && nUserSubCount > 1 )
+ {
+ aSubState.nRowSubTotalFunc = nUserPos;
+ aSubState.eRowForce = lcl_GetForceFunc( pParentLevel, nUserPos );
+ }
+
+ for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
+ {
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ nMemberMeasure = nSubCount;
+ else if ( pResultData->GetColStartMeasure() == SC_DPMEASURE_ALL )
+ nMemberMeasure = SC_DPMEASURE_ALL;
+
+ DBG_ASSERT( rRow < rSequence.getLength(), "bumm" );
+ uno::Sequence<sheet::DataResult>& rSubSeq = rSequence.getArray()[rRow];
+ long nSeqCol = 0;
+ pDataRoot->FillDataRow( pRefMember, rSubSeq, nSeqCol, nMemberMeasure, bHasChild, aSubState );
+
+ rRow += 1;
+ }
+ }
+ }
+ else
+ rRow += nSubSize * ( nUserSubCount - nUserSubStart ); // empty rows occur when ShowEmpty is true
+
+ // add extra space again if subtracted from GetSize above,
+ // add to own size if no children
+ rRow += nExtraSpace;
+
+ rRow += nMoveSubTotal;
+ }
+}
+
+void ScDPResultMember::UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const
+{
+ // IsVisible() test is in ScDPResultDimension::FillDataResults
+ // (not on data layout dimension)
+
+ BOOL bHasChild = ( pChildDimension != NULL );
+
+ long nUserSubCount = GetSubTotalCount();
+ // process subtotals even if not shown
+// if ( nUserSubCount || !bHasChild )
+ {
+ // Calculate at least automatic if no subtotals are selected,
+ // show only own values if there's no child dimension (innermost).
+ if ( !nUserSubCount || !bHasChild )
+ nUserSubCount = 1;
+
+ long nMemberMeasure = nMeasure;
+ long nSubSize = pResultData->GetCountForMeasure(nMeasure);
+
+ if ( pDataRoot )
+ {
+ ScDPSubTotalState aSubState; // initial state
+
+ for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
+ {
+ if ( bHasChild && nUserSubCount > 1 )
+ {
+ aSubState.nRowSubTotalFunc = nUserPos;
+ aSubState.eRowForce = lcl_GetForceFunc( pParentLevel, nUserPos );
+ }
+
+ for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
+ {
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ nMemberMeasure = nSubCount;
+ else if ( pResultData->GetColStartMeasure() == SC_DPMEASURE_ALL )
+ nMemberMeasure = SC_DPMEASURE_ALL;
+
+ pDataRoot->UpdateDataRow( pRefMember, nMemberMeasure, bHasChild, aSubState );
+ }
+ }
+ }
+ }
+
+ if (bHasChild) // child dimension must be processed last, so the column total is known
+ {
+ pChildDimension->UpdateDataResults( pRefMember, nMeasure );
+ }
+}
+
+void ScDPResultMember::SortMembers( ScDPResultMember* pRefMember )
+{
+ BOOL bHasChild = ( pChildDimension != NULL );
+ if (bHasChild)
+ pChildDimension->SortMembers( pRefMember ); // sorting is done at the dimension
+
+ BOOL bIsRoot = ( pParentLevel == NULL );
+ if ( bIsRoot && pDataRoot )
+ {
+ // use the row root member to sort columns
+ // sub total count is always 1
+
+ pDataRoot->SortMembers( pRefMember );
+ }
+}
+
+void ScDPResultMember::DoAutoShow( ScDPResultMember* pRefMember )
+{
+ BOOL bHasChild = ( pChildDimension != NULL );
+ if (bHasChild)
+ pChildDimension->DoAutoShow( pRefMember ); // sorting is done at the dimension
+
+ BOOL bIsRoot = ( pParentLevel == NULL );
+ if ( bIsRoot && pDataRoot )
+ {
+ // use the row root member to sort columns
+ // sub total count is always 1
+
+ pDataRoot->DoAutoShow( pRefMember );
+ }
+}
+
+void ScDPResultMember::ResetResults( BOOL bRoot )
+{
+ if (pDataRoot)
+ pDataRoot->ResetResults();
+
+ if (pChildDimension)
+ pChildDimension->ResetResults();
+
+ if (!bRoot)
+ bHasElements = FALSE;
+}
+
+void ScDPResultMember::UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure,
+ ScDPRunningTotalState& rRunning, ScDPRowTotals& rTotals ) const
+{
+ // IsVisible() test is in ScDPResultDimension::FillDataResults
+ // (not on data layout dimension)
+
+ BOOL bIsRoot = ( pParentLevel == NULL );
+ rTotals.SetInColRoot( bIsRoot );
+
+ BOOL bHasChild = ( pChildDimension != NULL );
+
+ long nUserSubCount = GetSubTotalCount();
+ if ( nUserSubCount || !bHasChild )
+ {
+ // Calculate at least automatic if no subtotals are selected,
+ // show only own values if there's no child dimension (innermost).
+ if ( !nUserSubCount || !bHasChild )
+ nUserSubCount = 1;
+
+ long nMemberMeasure = nMeasure;
+ long nSubSize = pResultData->GetCountForMeasure(nMeasure);
+
+ if ( pDataRoot )
+ {
+ ScDPSubTotalState aSubState; // initial state
+
+ for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
+ {
+ if ( bHasChild && nUserSubCount > 1 )
+ {
+ aSubState.nRowSubTotalFunc = nUserPos;
+ aSubState.eRowForce = lcl_GetForceFunc( pParentLevel, nUserPos );
+ }
+
+ for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
+ {
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ nMemberMeasure = nSubCount;
+ else if ( pResultData->GetColStartMeasure() == SC_DPMEASURE_ALL )
+ nMemberMeasure = SC_DPMEASURE_ALL;
+
+ pDataRoot->UpdateRunningTotals( pRefMember, nMemberMeasure,
+ bHasChild, aSubState, rRunning, rTotals, *this );
+ }
+ }
+ }
+ }
+
+ if (bHasChild) // child dimension must be processed last, so the column total is known
+ {
+ pChildDimension->UpdateRunningTotals( pRefMember, nMeasure, rRunning, rTotals );
+ }
+}
+
+void ScDPResultMember::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
+{
+ lcl_DumpRow( String::CreateFromAscii("ScDPResultMember"), GetName(), NULL, pDoc, rPos );
+ SCROW nStartRow = rPos.Row();
+
+ if (pDataRoot)
+ pDataRoot->DumpState( pRefMember, pDoc, rPos );
+
+ if (pChildDimension)
+ pChildDimension->DumpState( pRefMember, pDoc, rPos );
+
+ lcl_Indent( pDoc, nStartRow, rPos );
+}
+
+ScDPAggData* ScDPResultMember::GetColTotal( long nMeasure ) const
+{
+ return lcl_GetChildTotal( const_cast<ScDPAggData*>(&aColTotal), nMeasure );
+}
+
+void ScDPResultMember::FillVisibilityData(ScDPResultVisibilityData& rData) const
+{
+ if (pChildDimension)
+ pChildDimension->FillVisibilityData(rData);
+}
+
+// -----------------------------------------------------------------------
+
+ScDPDataMember::ScDPDataMember( const ScDPResultData* pData, const ScDPResultMember* pRes ) :
+ pResultData( pData ),
+ pResultMember( pRes ),
+ pChildDimension( NULL )
+{
+ // pResultMember is 0 for root members
+}
+
+ScDPDataMember::~ScDPDataMember()
+{
+ delete pChildDimension;
+}
+
+String ScDPDataMember::GetName() const
+{
+ if (pResultMember)
+ return pResultMember->GetName();
+ else
+ return EMPTY_STRING;
+}
+
+BOOL ScDPDataMember::IsVisible() const
+{
+ if (pResultMember)
+ return pResultMember->IsVisible();
+ else
+ return FALSE;
+}
+
+BOOL ScDPDataMember::IsNamedItem( const ScDPItemData& r ) const
+{
+ if (pResultMember)
+ return pResultMember->IsNamedItem(r);
+ else
+ return FALSE;
+}
+
+BOOL ScDPDataMember::HasHiddenDetails() const
+{
+ if (pResultMember)
+ return pResultMember->HasHiddenDetails();
+ else
+ return FALSE;
+}
+
+void ScDPDataMember::InitFrom( const ScDPResultDimension* pDim )
+{
+ if ( !pChildDimension )
+ pChildDimension = new ScDPDataDimension(pResultData);
+ pChildDimension->InitFrom(pDim);
+}
+
+const long SC_SUBTOTALPOS_AUTO = -1; // default
+const long SC_SUBTOTALPOS_SKIP = -2; // don't use
+
+long lcl_GetSubTotalPos( const ScDPSubTotalState& rSubState )
+{
+ if ( rSubState.nColSubTotalFunc >= 0 && rSubState.nRowSubTotalFunc >= 0 &&
+ rSubState.nColSubTotalFunc != rSubState.nRowSubTotalFunc )
+ {
+ // #i68338# don't return the same index for different combinations (leading to repeated updates),
+ // return a "don't use" value instead
+
+ return SC_SUBTOTALPOS_SKIP;
+ }
+
+ long nRet = SC_SUBTOTALPOS_AUTO;
+ if ( rSubState.nColSubTotalFunc >= 0 ) nRet = rSubState.nColSubTotalFunc;
+ if ( rSubState.nRowSubTotalFunc >= 0 ) nRet = rSubState.nRowSubTotalFunc;
+ return nRet;
+}
+
+void ScDPDataMember::UpdateValues( const vector<ScDPValueData>& aValues, const ScDPSubTotalState& rSubState )
+{
+ //! find out how many and which subtotals are used
+
+ ScDPAggData* pAgg = &aAggregate;
+
+ long nSubPos = lcl_GetSubTotalPos(rSubState);
+ if (nSubPos == SC_SUBTOTALPOS_SKIP)
+ return;
+ if (nSubPos > 0)
+ {
+ long nSkip = nSubPos * pResultData->GetMeasureCount();
+ for (long i=0; i<nSkip; i++)
+ pAgg = pAgg->GetChild(); // created if not there
+ }
+
+ size_t nCount = aValues.size();
+ for (size_t nPos = 0; nPos < nCount; ++nPos)
+ {
+ pAgg->Update(aValues[nPos], pResultData->GetMeasureFunction(nPos), rSubState);
+ pAgg = pAgg->GetChild();
+ }
+}
+
+void ScDPDataMember::ProcessData( const vector<ScDPItemData>& aChildMembers, const vector<ScDPValueData>& aValues,
+ const ScDPSubTotalState& rSubState )
+{
+ if ( pResultData->IsLateInit() && !pChildDimension && pResultMember && pResultMember->GetChildDimension() )
+ {
+ // if this DataMember doesn't have a child dimension because the ResultMember's
+ // child dimension wasn't there yet during this DataMembers's creation,
+ // create the child dimension now
+ InitFrom( pResultMember->GetChildDimension() );
+ }
+
+ ScDPSubTotalState aLocalSubState(rSubState); // keep row state, modify column
+
+ long nUserSubCount = pResultMember ? pResultMember->GetSubTotalCount() : 0;
+
+ // Calculate at least automatic if no subtotals are selected,
+ // show only own values if there's no child dimension (innermost).
+ if ( !nUserSubCount || !pChildDimension )
+ nUserSubCount = 1;
+
+ for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
+ {
+ if ( pChildDimension && nUserSubCount > 1 )
+ {
+ const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
+ aLocalSubState.nColSubTotalFunc = nUserPos;
+ aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
+ }
+
+ UpdateValues( aValues, aLocalSubState );
+ }
+
+ if (pChildDimension)
+ pChildDimension->ProcessData( aChildMembers, aValues, rSubState ); // with unmodified subtotal state
+}
+
+BOOL ScDPDataMember::HasData( long nMeasure, const ScDPSubTotalState& rSubState ) const
+{
+ if ( rSubState.eColForce != SUBTOTAL_FUNC_NONE && rSubState.eRowForce != SUBTOTAL_FUNC_NONE &&
+ rSubState.eColForce != rSubState.eRowForce )
+ return FALSE;
+
+ // #74542# HasData can be different between measures!
+
+ const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
+ if (!pAgg)
+ return FALSE; //! error?
+
+ return pAgg->HasData();
+}
+
+BOOL ScDPDataMember::HasError( long nMeasure, const ScDPSubTotalState& rSubState ) const
+{
+ const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
+ if (!pAgg)
+ return TRUE;
+
+ return pAgg->HasError();
+}
+
+double ScDPDataMember::GetAggregate( long nMeasure, const ScDPSubTotalState& rSubState ) const
+{
+ const ScDPAggData* pAgg = GetConstAggData( nMeasure, rSubState );
+ if (!pAgg)
+ return DBL_MAX; //! error?
+
+ return pAgg->GetResult();
+}
+
+ScDPAggData* ScDPDataMember::GetAggData( long nMeasure, const ScDPSubTotalState& rSubState )
+{
+ DBG_ASSERT( nMeasure >= 0, "GetAggData: no measure" );
+
+ ScDPAggData* pAgg = &aAggregate;
+ long nSkip = nMeasure;
+ long nSubPos = lcl_GetSubTotalPos(rSubState);
+ if (nSubPos == SC_SUBTOTALPOS_SKIP)
+ return NULL;
+ if (nSubPos > 0)
+ nSkip += nSubPos * pResultData->GetMeasureCount();
+
+ for ( long nPos=0; nPos<nSkip; nPos++ )
+ pAgg = pAgg->GetChild(); //! need to create children here?
+
+ return pAgg;
+}
+
+const ScDPAggData* ScDPDataMember::GetConstAggData( long nMeasure, const ScDPSubTotalState& rSubState ) const
+{
+ DBG_ASSERT( nMeasure >= 0, "GetConstAggData: no measure" );
+
+ const ScDPAggData* pAgg = &aAggregate;
+ long nSkip = nMeasure;
+ long nSubPos = lcl_GetSubTotalPos(rSubState);
+ if (nSubPos == SC_SUBTOTALPOS_SKIP)
+ return NULL;
+ if (nSubPos > 0)
+ nSkip += nSubPos * pResultData->GetMeasureCount();
+
+ for ( long nPos=0; nPos<nSkip; nPos++ )
+ {
+ pAgg = pAgg->GetExistingChild();
+ if (!pAgg)
+ return NULL;
+ }
+
+ return pAgg;
+}
+
+void ScDPDataMember::FillDataRow( const ScDPResultMember* pRefMember,
+ uno::Sequence<sheet::DataResult>& rSequence,
+ long& rCol, long nMeasure, BOOL bIsSubTotalRow,
+ const ScDPSubTotalState& rSubState ) const
+{
+ DBG_ASSERT( pRefMember == pResultMember || !pResultMember, "bla" );
+
+ if ( pRefMember->IsVisible() ) //! here or in ScDPDataDimension::FillDataRow ???
+ {
+ long nStartCol = rCol;
+
+ const ScDPDataDimension* pDataChild = GetChildDimension();
+ const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
+
+ const ScDPLevel* pRefParentLevel = const_cast<ScDPResultMember*>(pRefMember)->GetParentLevel();
+
+ long nExtraSpace = 0;
+ if ( pRefParentLevel && pRefParentLevel->IsAddEmpty() )
+ ++nExtraSpace;
+
+ BOOL bTitleLine = FALSE;
+ if ( pRefParentLevel && pRefParentLevel->IsOutlineLayout() )
+ bTitleLine = TRUE;
+
+ BOOL bSubTotalInTitle = pRefMember->IsSubTotalInTitle( nMeasure );
+
+ // leave space for children even if the DataMember hasn't been initialized
+ // (pDataChild is null then, this happens when no values for it are in this row)
+ BOOL bHasChild = ( pRefChild != NULL );
+
+ if ( bHasChild )
+ {
+ if ( bTitleLine ) // in tabular layout the title is on a separate column
+ ++rCol; // -> fill child dimension one column below
+
+ if ( pDataChild )
+ pDataChild->FillDataRow( pRefChild, rSequence, rCol, nMeasure, bIsSubTotalRow, rSubState );
+ rCol += (USHORT)pRefMember->GetSize( nMeasure );
+
+ if ( bTitleLine ) // title column is included in GetSize, so the following
+ --rCol; // positions are calculated with the normal values
+ }
+
+ long nUserSubStart;
+ long nUserSubCount = pRefMember->GetSubTotalCount(&nUserSubStart);
+ if ( nUserSubCount || !bHasChild )
+ {
+ // Calculate at least automatic if no subtotals are selected,
+ // show only own values if there's no child dimension (innermost).
+ if ( !nUserSubCount || !bHasChild )
+ {
+ nUserSubCount = 1;
+ nUserSubStart = 0;
+ }
+
+ ScDPSubTotalState aLocalSubState(rSubState); // keep row state, modify column
+
+ long nMemberMeasure = nMeasure;
+ long nSubSize = pResultData->GetCountForMeasure(nMeasure);
+ if (bHasChild)
+ {
+ rCol -= nSubSize * ( nUserSubCount - nUserSubStart ); // GetSize includes space for SubTotal
+ rCol -= nExtraSpace; // GetSize includes the empty line
+ }
+
+ long nMoveSubTotal = 0;
+ if ( bSubTotalInTitle )
+ {
+ nMoveSubTotal = rCol - nStartCol; // force to first (title) column
+ rCol = nStartCol;
+ }
+
+ for (long nUserPos=nUserSubStart; nUserPos<nUserSubCount; nUserPos++)
+ {
+ if ( pChildDimension && nUserSubCount > 1 )
+ {
+ const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
+ aLocalSubState.nColSubTotalFunc = nUserPos;
+ aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
+ }
+
+ for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
+ {
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ nMemberMeasure = nSubCount;
+
+ DBG_ASSERT( rCol < rSequence.getLength(), "bumm" );
+ sheet::DataResult& rRes = rSequence.getArray()[rCol];
+
+ if ( HasData( nMemberMeasure, aLocalSubState ) )
+ {
+ if ( HasError( nMemberMeasure, aLocalSubState ) )
+ {
+ rRes.Value = 0;
+ rRes.Flags |= sheet::DataResultFlags::ERROR;
+ }
+ else
+ {
+ rRes.Value = GetAggregate( nMemberMeasure, aLocalSubState );
+ rRes.Flags |= sheet::DataResultFlags::HASDATA;
+ }
+ }
+
+ if ( bHasChild || bIsSubTotalRow )
+ rRes.Flags |= sheet::DataResultFlags::SUBTOTAL;
+
+ rCol += 1;
+ }
+ }
+
+ // add extra space again if subtracted from GetSize above,
+ // add to own size if no children
+ rCol += nExtraSpace;
+
+ rCol += nMoveSubTotal;
+ }
+ }
+}
+
+void ScDPDataMember::UpdateDataRow( const ScDPResultMember* pRefMember,
+ long nMeasure, BOOL bIsSubTotalRow,
+ const ScDPSubTotalState& rSubState )
+{
+ DBG_ASSERT( pRefMember == pResultMember || !pResultMember, "bla" );
+
+ // Calculate must be called even if not visible (for use as reference value)
+ const ScDPDataDimension* pDataChild = GetChildDimension();
+ const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
+
+ // leave space for children even if the DataMember hasn't been initialized
+ // (pDataChild is null then, this happens when no values for it are in this row)
+ BOOL bHasChild = ( pRefChild != NULL );
+
+ // process subtotals even if not shown
+ long nUserSubCount = pRefMember->GetSubTotalCount();
+
+ // Calculate at least automatic if no subtotals are selected,
+ // show only own values if there's no child dimension (innermost).
+ if ( !nUserSubCount || !bHasChild )
+ nUserSubCount = 1;
+
+ ScDPSubTotalState aLocalSubState(rSubState); // keep row state, modify column
+
+ long nMemberMeasure = nMeasure;
+ long nSubSize = pResultData->GetCountForMeasure(nMeasure);
+
+ for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
+ {
+ if ( pChildDimension && nUserSubCount > 1 )
+ {
+ const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
+ aLocalSubState.nColSubTotalFunc = nUserPos;
+ aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
+ }
+
+ for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
+ {
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ nMemberMeasure = nSubCount;
+
+ // update data...
+ ScDPAggData* pAggData = GetAggData( nMemberMeasure, aLocalSubState );
+ if (pAggData)
+ {
+ //! aLocalSubState?
+ ScSubTotalFunc eFunc = pResultData->GetMeasureFunction( nMemberMeasure );
+ sheet::DataPilotFieldReference aReferenceValue = pResultData->GetMeasureRefVal( nMemberMeasure );
+ sal_Int32 eRefType = aReferenceValue.ReferenceType;
+
+ // calculate the result first - for all members, regardless of reference value
+ pAggData->Calculate( eFunc, aLocalSubState );
+
+ if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
+ eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
+ eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE )
+ {
+ // copy the result into auxiliary value, so differences can be
+ // calculated in any order
+ pAggData->SetAuxiliary( pAggData->GetResult() );
+ }
+ // column/row percentage/index is now in UpdateRunningTotals, so it doesn't disturb sorting
+ }
+ }
+ }
+
+ if ( bHasChild ) // child dimension must be processed last, so the row total is known
+ {
+ if ( pDataChild )
+ pDataChild->UpdateDataRow( pRefChild, nMeasure, bIsSubTotalRow, rSubState );
+ }
+}
+
+void ScDPDataMember::SortMembers( ScDPResultMember* pRefMember )
+{
+ DBG_ASSERT( pRefMember == pResultMember || !pResultMember, "bla" );
+
+ if ( pRefMember->IsVisible() ) //! here or in ScDPDataDimension ???
+ {
+ ScDPDataDimension* pDataChild = GetChildDimension();
+ ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
+ if ( pRefChild && pDataChild )
+ pDataChild->SortMembers( pRefChild ); // sorting is done at the dimension
+ }
+}
+
+void ScDPDataMember::DoAutoShow( ScDPResultMember* pRefMember )
+{
+ DBG_ASSERT( pRefMember == pResultMember || !pResultMember, "bla" );
+
+ if ( pRefMember->IsVisible() ) //! here or in ScDPDataDimension ???
+ {
+ ScDPDataDimension* pDataChild = GetChildDimension();
+ ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
+ if ( pRefChild && pDataChild )
+ pDataChild->DoAutoShow( pRefChild ); // sorting is done at the dimension
+ }
+}
+
+void ScDPDataMember::ResetResults()
+{
+ aAggregate.Reset();
+
+ ScDPDataDimension* pDataChild = GetChildDimension();
+ if ( pDataChild )
+ pDataChild->ResetResults();
+}
+
+void ScDPDataMember::UpdateRunningTotals( const ScDPResultMember* pRefMember,
+ long nMeasure, BOOL bIsSubTotalRow,
+ const ScDPSubTotalState& rSubState, ScDPRunningTotalState& rRunning,
+ ScDPRowTotals& rTotals, const ScDPResultMember& rRowParent )
+{
+ DBG_ASSERT( pRefMember == pResultMember || !pResultMember, "bla" );
+
+ if ( pRefMember->IsVisible() ) //! here or in ScDPDataDimension::UpdateRunningTotals ???
+ {
+ const ScDPDataDimension* pDataChild = GetChildDimension();
+ const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
+
+ BOOL bIsRoot = ( pResultMember == NULL || pResultMember->GetParentLevel() == NULL );
+
+ // leave space for children even if the DataMember hasn't been initialized
+ // (pDataChild is null then, this happens when no values for it are in this row)
+ BOOL bHasChild = ( pRefChild != NULL );
+
+ long nUserSubCount = pRefMember->GetSubTotalCount();
+ if ( nUserSubCount || !bHasChild )
+ {
+ // Calculate at least automatic if no subtotals are selected,
+ // show only own values if there's no child dimension (innermost).
+ if ( !nUserSubCount || !bHasChild )
+ nUserSubCount = 1;
+
+ ScDPSubTotalState aLocalSubState(rSubState); // keep row state, modify column
+
+ long nMemberMeasure = nMeasure;
+ long nSubSize = pResultData->GetCountForMeasure(nMeasure);
+
+ for (long nUserPos=0; nUserPos<nUserSubCount; nUserPos++) // including hidden "automatic"
+ {
+ if ( pChildDimension && nUserSubCount > 1 )
+ {
+ const ScDPLevel* pForceLevel = pResultMember ? pResultMember->GetParentLevel() : NULL;
+ aLocalSubState.nColSubTotalFunc = nUserPos;
+ aLocalSubState.eColForce = lcl_GetForceFunc( pForceLevel, nUserPos );
+ }
+
+ for ( long nSubCount=0; nSubCount<nSubSize; nSubCount++ )
+ {
+ if ( nMeasure == SC_DPMEASURE_ALL )
+ nMemberMeasure = nSubCount;
+
+ // update data...
+ ScDPAggData* pAggData = GetAggData( nMemberMeasure, aLocalSubState );
+ if (pAggData)
+ {
+ //! aLocalSubState?
+ sheet::DataPilotFieldReference aReferenceValue = pResultData->GetMeasureRefVal( nMemberMeasure );
+ sal_Int32 eRefType = aReferenceValue.ReferenceType;
+
+ if ( eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL ||
+ eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
+ eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
+ eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE )
+ {
+ BOOL bRunningTotal = ( eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL );
+ BOOL bRelative =
+ ( aReferenceValue.ReferenceItemType != sheet::DataPilotFieldReferenceItemType::NAMED && !bRunningTotal );
+ long nRelativeDir = bRelative ?
+ ( ( aReferenceValue.ReferenceItemType == sheet::DataPilotFieldReferenceItemType::PREVIOUS ) ? -1 : 1 ) : 0;
+
+ const long* pColVisible = rRunning.GetColVisible();
+ const long* pColIndexes = rRunning.GetColIndexes();
+ const long* pRowVisible = rRunning.GetRowVisible();
+ const long* pRowIndexes = rRunning.GetRowIndexes();
+
+ String aRefFieldName = aReferenceValue.ReferenceField;
+
+ //! aLocalSubState?
+ USHORT nRefOrient = pResultData->GetMeasureRefOrient( nMemberMeasure );
+ BOOL bRefDimInCol = ( nRefOrient == sheet::DataPilotFieldOrientation_COLUMN );
+ BOOL bRefDimInRow = ( nRefOrient == sheet::DataPilotFieldOrientation_ROW );
+
+ const ScDPResultDimension* pSelectDim = NULL;
+ long nRowPos = 0;
+ long nColPos = 0;
+
+ //
+ // find the reference field in column or row dimensions
+ //
+
+ if ( bRefDimInRow ) // look in row dimensions
+ {
+ pSelectDim = rRunning.GetRowResRoot()->GetChildDimension();
+ while ( pSelectDim && pSelectDim->GetName() != aRefFieldName )
+ {
+ long nIndex = pRowIndexes[nRowPos];
+ if ( nIndex >= 0 && nIndex < pSelectDim->GetMemberCount() )
+ pSelectDim = pSelectDim->GetMember(nIndex)->GetChildDimension();
+ else
+ pSelectDim = NULL;
+ ++nRowPos;
+ }
+ // child dimension of innermost member?
+ if ( pSelectDim && pRowIndexes[nRowPos] < 0 )
+ pSelectDim = NULL;
+ }
+
+ if ( bRefDimInCol ) // look in column dimensions
+ {
+ pSelectDim = rRunning.GetColResRoot()->GetChildDimension();
+ while ( pSelectDim && pSelectDim->GetName() != aRefFieldName )
+ {
+ long nIndex = pColIndexes[nColPos];
+ if ( nIndex >= 0 && nIndex < pSelectDim->GetMemberCount() )
+ pSelectDim = pSelectDim->GetMember(nIndex)->GetChildDimension();
+ else
+ pSelectDim = NULL;
+ ++nColPos;
+ }
+ // child dimension of innermost member?
+ if ( pSelectDim && pColIndexes[nColPos] < 0 )
+ pSelectDim = NULL;
+ }
+
+ BOOL bNoDetailsInRef = FALSE;
+ if ( pSelectDim && bRunningTotal )
+ {
+ // Running totals:
+ // If details are hidden for this member in the reference dimension,
+ // don't show or sum up the value. Otherwise, for following members,
+ // the running totals of details and subtotals wouldn't match.
+
+ long nMyIndex = bRefDimInCol ? pColIndexes[nColPos] : pRowIndexes[nRowPos];
+ if ( nMyIndex >= 0 && nMyIndex < pSelectDim->GetMemberCount() )
+ {
+ const ScDPResultMember* pMyRefMember = pSelectDim->GetMember(nMyIndex);
+ if ( pMyRefMember && pMyRefMember->HasHiddenDetails() )
+ {
+ pSelectDim = NULL; // don't calculate
+ bNoDetailsInRef = TRUE; // show error, not empty
+ }
+ }
+ }
+
+ if ( bRelative )
+ {
+ // Difference/Percentage from previous/next:
+ // If details are hidden for this member in the innermost column/row
+ // dimension (the orientation of the reference dimension), show an
+ // error value.
+ // - If the no-details dimension is the reference dimension, its
+ // members will be skipped when finding the previous/next member,
+ // so there must be no results for its members.
+ // - If the no-details dimension is outside of the reference dimension,
+ // no calculation in the reference dimension is possible.
+ // - Otherwise, the error isn't strictly necessary, but shown for
+ // consistency.
+
+ BOOL bInnerNoDetails = bRefDimInCol ? HasHiddenDetails() :
+ ( bRefDimInRow ? rRowParent.HasHiddenDetails() : TRUE );
+ if ( bInnerNoDetails )
+ {
+ pSelectDim = NULL;
+ bNoDetailsInRef = TRUE; // show error, not empty
+ }
+ }
+
+ if ( !bRefDimInCol && !bRefDimInRow ) // invalid dimension specified
+ bNoDetailsInRef = TRUE; // pSelectDim is then already NULL
+
+ //
+ // get the member for the reference item and do the calculation
+ //
+
+ if ( bRunningTotal )
+ {
+ // running total in (dimension) -> find first existing member
+
+ if ( pSelectDim )
+ {
+ ScDPDataMember* pSelectMember;
+ if ( bRefDimInCol )
+ pSelectMember = ScDPResultDimension::GetColReferenceMember( NULL, NULL,
+ nColPos, rRunning );
+ else
+ {
+ long nSkip = nRowPos + 1; // including the reference dimension
+ pSelectMember = pSelectDim->GetRowReferenceMember( NULL, NULL,
+ pRowIndexes+nSkip, pColIndexes );
+ }
+
+ if ( pSelectMember )
+ {
+ // The running total is kept as the auxiliary value in
+ // the first available member for the reference dimension.
+ // Members are visited in final order, so each one's result
+ // can be used and then modified.
+
+ ScDPAggData* pSelectData = pSelectMember->
+ GetAggData( nMemberMeasure, aLocalSubState );
+ if ( pSelectData )
+ {
+ double fTotal = pSelectData->GetAuxiliary();
+ fTotal += pAggData->GetResult();
+ pSelectData->SetAuxiliary( fTotal );
+ pAggData->SetResult( fTotal );
+ pAggData->SetEmpty(FALSE); // always display
+ }
+ }
+ else
+ pAggData->SetError();
+ }
+ else if (bNoDetailsInRef)
+ pAggData->SetError();
+ else
+ pAggData->SetEmpty(TRUE); // empty (dim set to 0 above)
+ }
+ else
+ {
+ // difference/percentage -> find specified member
+
+ if ( pSelectDim )
+ {
+ String aRefItemName = aReferenceValue.ReferenceItemName;
+ ScDPRelativePos aRefItemPos( 0, nRelativeDir ); // nBasePos is modified later
+
+ const String* pRefName = NULL;
+ const ScDPRelativePos* pRefPos = NULL;
+ if ( bRelative )
+ pRefPos = &aRefItemPos;
+ else
+ pRefName = &aRefItemName;
+
+ ScDPDataMember* pSelectMember;
+ if ( bRefDimInCol )
+ {
+ aRefItemPos.nBasePos = pColVisible[nColPos]; // without sort order applied
+ pSelectMember = ScDPResultDimension::GetColReferenceMember( pRefPos, pRefName,
+ nColPos, rRunning );
+ }
+ else
+ {
+ aRefItemPos.nBasePos = pRowVisible[nRowPos]; // without sort order applied
+ long nSkip = nRowPos + 1; // including the reference dimension
+ pSelectMember = pSelectDim->GetRowReferenceMember( pRefPos, pRefName,
+ pRowIndexes+nSkip, pColIndexes );
+ }
+
+ // difference or perc.difference is empty for the reference item itself
+ if ( pSelectMember == this &&
+ eRefType != sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE )
+ {
+ pAggData->SetEmpty(TRUE);
+ }
+ else if ( pSelectMember )
+ {
+ const ScDPAggData* pOtherAggData = pSelectMember->
+ GetConstAggData( nMemberMeasure, aLocalSubState );
+ DBG_ASSERT( pOtherAggData, "no agg data" );
+ if ( pOtherAggData )
+ {
+ // Reference member may be visited before or after this one,
+ // so the auxiliary value is used for the original result.
+
+ double fOtherResult = pOtherAggData->GetAuxiliary();
+ double fThisResult = pAggData->GetResult();
+ BOOL bError = FALSE;
+ switch ( eRefType )
+ {
+ case sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE:
+ fThisResult = fThisResult - fOtherResult;
+ break;
+ case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE:
+ if ( fOtherResult == 0.0 )
+ bError = TRUE;
+ else
+ fThisResult = fThisResult / fOtherResult;
+ break;
+ case sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
+ if ( fOtherResult == 0.0 )
+ bError = TRUE;
+ else
+ fThisResult = ( fThisResult - fOtherResult ) / fOtherResult;
+ break;
+ default:
+ DBG_ERROR("invalid calculation type");
+ }
+ if ( bError )
+ {
+ pAggData->SetError();
+ }
+ else
+ {
+ pAggData->SetResult(fThisResult);
+ pAggData->SetEmpty(FALSE); // always display
+ }
+ //! errors in data?
+ }
+ }
+ else if (bRelative && !bNoDetailsInRef)
+ pAggData->SetEmpty(TRUE); // empty
+ else
+ pAggData->SetError(); // error
+ }
+ else if (bNoDetailsInRef)
+ pAggData->SetError(); // error
+ else
+ pAggData->SetEmpty(TRUE); // empty
+ }
+ }
+ else if ( eRefType == sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE ||
+ eRefType == sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE ||
+ eRefType == sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE ||
+ eRefType == sheet::DataPilotFieldReferenceType::INDEX )
+ {
+ //
+ // set total values when they are encountered (always before their use)
+ //
+
+ ScDPAggData* pColTotalData = pRefMember->GetColTotal( nMemberMeasure );
+ ScDPAggData* pRowTotalData = rTotals.GetRowTotal( nMemberMeasure );
+ ScDPAggData* pGrandTotalData = rTotals.GetGrandTotal( nMemberMeasure );
+
+ double fTotalValue = pAggData->HasError() ? 0 : pAggData->GetResult();
+
+ if ( bIsRoot && rTotals.IsInColRoot() && pGrandTotalData )
+ pGrandTotalData->SetAuxiliary( fTotalValue );
+
+ if ( bIsRoot && pRowTotalData )
+ pRowTotalData->SetAuxiliary( fTotalValue );
+
+ if ( rTotals.IsInColRoot() && pColTotalData )
+ pColTotalData->SetAuxiliary( fTotalValue );
+
+ //
+ // find relation to total values
+ //
+
+ switch ( eRefType )
+ {
+ case sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE:
+ case sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
+ case sheet::DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
+ {
+ double nTotal;
+ if ( eRefType == sheet::DataPilotFieldReferenceType::ROW_PERCENTAGE )
+ nTotal = pRowTotalData->GetAuxiliary();
+ else if ( eRefType == sheet::DataPilotFieldReferenceType::COLUMN_PERCENTAGE )
+ nTotal = pColTotalData->GetAuxiliary();
+ else
+ nTotal = pGrandTotalData->GetAuxiliary();
+
+ if ( nTotal == 0.0 )
+ pAggData->SetError();
+ else
+ pAggData->SetResult( pAggData->GetResult() / nTotal );
+ }
+ break;
+ case sheet::DataPilotFieldReferenceType::INDEX:
+ {
+ double nColTotal = pColTotalData->GetAuxiliary();
+ double nRowTotal = pRowTotalData->GetAuxiliary();
+ double nGrandTotal = pGrandTotalData->GetAuxiliary();
+ if ( nRowTotal == 0.0 || nColTotal == 0.0 )
+ pAggData->SetError();
+ else
+ pAggData->SetResult(
+ ( pAggData->GetResult() * nGrandTotal ) /
+ ( nRowTotal * nColTotal ) );
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( bHasChild ) // child dimension must be processed last, so the row total is known
+ {
+ if ( pDataChild )
+ pDataChild->UpdateRunningTotals( pRefChild, nMeasure,
+ bIsSubTotalRow, rSubState, rRunning, rTotals, rRowParent );
+ }
+ }
+}
+
+void ScDPDataMember::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
+{
+ lcl_DumpRow( String::CreateFromAscii("ScDPDataMember"), GetName(), &aAggregate, pDoc, rPos );
+ SCROW nStartRow = rPos.Row();
+
+ const ScDPDataDimension* pDataChild = GetChildDimension();
+ const ScDPResultDimension* pRefChild = pRefMember->GetChildDimension();
+ if ( pDataChild && pRefChild )
+ pDataChild->DumpState( pRefChild, pDoc, rPos );
+
+ lcl_Indent( pDoc, nStartRow, rPos );
+}
+
+// -----------------------------------------------------------------------
+
+// Helper class to select the members to include in
+// ScDPResultDimension::InitFrom or LateInitFrom if groups are used
+
+class ScDPGroupCompare
+{
+private:
+ const ScDPResultData* pResultData;
+ const ScDPInitState& rInitState;
+ long nDimSource;
+ BOOL bIncludeAll;
+ BOOL bIsBase;
+ long nGroupBase;
+ const ScDPItemData* pBaseData;
+
+public:
+ ScDPGroupCompare( const ScDPResultData* pData, const ScDPInitState& rState, long nDimension );
+ ~ScDPGroupCompare() {}
+
+ BOOL IsIncluded( const ScDPMember& rMember ) { return bIncludeAll || TestIncluded( rMember ); }
+ BOOL TestIncluded( const ScDPMember& rMember );
+};
+
+ScDPGroupCompare::ScDPGroupCompare( const ScDPResultData* pData, const ScDPInitState& rState, long nDimension ) :
+ pResultData( pData ),
+ rInitState( rState ),
+ nDimSource( nDimension ),
+ pBaseData( NULL )
+{
+ bIsBase = pResultData->IsBaseForGroup( nDimSource );
+ nGroupBase = pResultData->GetGroupBase( nDimSource ); //! get together in one call?
+ if ( nGroupBase >= 0 )
+ pBaseData = rInitState.GetNameForIndex( nGroupBase );
+
+ // if bIncludeAll is set, TestIncluded doesn't need to be called
+ bIncludeAll = !( bIsBase || nGroupBase >= 0 );
+}
+
+BOOL ScDPGroupCompare::TestIncluded( const ScDPMember& rMember )
+{
+ BOOL bInclude = TRUE;
+ if ( pBaseData )
+ {
+ ScDPItemData aMemberData;
+ rMember.FillItemData( aMemberData );
+ bInclude = pResultData->IsInGroup( aMemberData, nDimSource, *pBaseData, nGroupBase );
+ }
+ else if ( bIsBase )
+ {
+ // need to check all previous groups
+ //! get array of groups (or indexes) before loop?
+ ScDPItemData aMemberData;
+ rMember.FillItemData( aMemberData );
+ long nInitCount = rInitState.GetCount();
+ const long* pInitSource = rInitState.GetSource();
+ const ScDPItemData* pInitNames = rInitState.GetNames();
+ for (long nInitPos=0; nInitPos<nInitCount && bInclude; nInitPos++)
+ if ( pResultData->GetGroupBase( pInitSource[nInitPos] ) == nDimSource )
+ {
+ bInclude = pResultData->IsInGroup( pInitNames[nInitPos], pInitSource[nInitPos],
+ aMemberData, nDimSource );
+ }
+ }
+ else if ( nGroupBase >= 0 )
+ {
+ // base isn't used in preceding fields
+ // -> look for other groups using the same base
+
+ //! get array of groups (or indexes) before loop?
+ ScDPItemData aMemberData;
+ rMember.FillItemData( aMemberData );
+ long nInitCount = rInitState.GetCount();
+ const long* pInitSource = rInitState.GetSource();
+ const ScDPItemData* pInitNames = rInitState.GetNames();
+ for (long nInitPos=0; nInitPos<nInitCount && bInclude; nInitPos++)
+ if ( pResultData->GetGroupBase( pInitSource[nInitPos] ) == nGroupBase )
+ {
+ // same base (hierarchy between the two groups is irrelevant)
+ bInclude = pResultData->HasCommonElement( pInitNames[nInitPos], pInitSource[nInitPos],
+ aMemberData, nDimSource );
+ }
+ }
+
+ return bInclude;
+}
+
+// -----------------------------------------------------------------------
+
+ScDPResultDimension::ScDPResultDimension( const ScDPResultData* pData ) :
+ pResultData( pData ),
+ bInitialized( FALSE ),
+ bIsDataLayout( FALSE ),
+ bSortByData( FALSE ),
+ bSortAscending( FALSE ),
+ nSortMeasure( 0 ),
+ bAutoShow( FALSE ),
+ bAutoTopItems( FALSE ),
+ nAutoMeasure( 0 ),
+ nAutoCount( 0 )
+{
+}
+
+ScDPResultDimension::~ScDPResultDimension()
+{
+ for( int i = maMemberArray.size () ; i-- > 0 ; )
+ delete maMemberArray[i];
+}
+
+ScDPResultMember *ScDPResultDimension::FindMember( const ScDPItemData& rData ) const
+{
+ if( bIsDataLayout )
+ return maMemberArray[0];
+
+ MemberHash::const_iterator aRes = maMemberHash.find( rData );
+ if( aRes != maMemberHash.end()) {
+ if ( aRes->second->IsNamedItem( rData ) )
+ return aRes->second;
+ DBG_ERROR("problem! hash result is not the same as IsNamedItem");
+ }
+
+ unsigned int i;
+ unsigned int nCount = maMemberArray.size();
+ ScDPResultMember* pResultMember;
+ for( i = 0; i < nCount ; i++ )
+ {
+ pResultMember = maMemberArray[i];
+ if ( pResultMember->IsNamedItem( rData ) )
+ return pResultMember;
+ }
+ return NULL;
+}
+
+void ScDPResultDimension::InitFrom( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev,
+ size_t nPos, ScDPInitState& rInitState )
+{
+ if (nPos >= ppDim.size() || nPos >= ppLev.size())
+ {
+ bInitialized = true;
+ return;
+ }
+
+ ScDPDimension* pThisDim = ppDim[nPos];
+ ScDPLevel* pThisLevel = ppLev[nPos];
+
+ if (!pThisDim || !pThisLevel)
+ {
+ bInitialized = true;
+ return;
+ }
+
+ bIsDataLayout = pThisDim->getIsDataLayoutDimension(); // member
+ aDimensionName = pThisDim->getName(); // member
+
+ // Check the autoshow setting. If it's enabled, store the settings.
+ const sheet::DataPilotFieldAutoShowInfo& rAutoInfo = pThisLevel->GetAutoShow();
+ if ( rAutoInfo.IsEnabled )
+ {
+ bAutoShow = TRUE;
+ bAutoTopItems = ( rAutoInfo.ShowItemsMode == sheet::DataPilotFieldShowItemsMode::FROM_TOP );
+ nAutoMeasure = pThisLevel->GetAutoMeasure();
+ nAutoCount = rAutoInfo.ItemCount;
+ }
+
+ // Check the sort info, and store the settings if appropriate.
+ const sheet::DataPilotFieldSortInfo& rSortInfo = pThisLevel->GetSortInfo();
+ if ( rSortInfo.Mode == sheet::DataPilotFieldSortMode::DATA )
+ {
+ bSortByData = TRUE;
+ bSortAscending = rSortInfo.IsAscending;
+ nSortMeasure = pThisLevel->GetSortMeasure();
+ }
+
+ // global order is used to initialize aMembers, so it doesn't have to be looked at later
+ const ScMemberSortOrder& rGlobalOrder = pThisLevel->GetGlobalOrder();
+
+ long nDimSource = pThisDim->GetDimension(); //! check GetSourceDim?
+ ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
+
+ // Now, go through all members and initialize them.
+ ScDPMembers* pMembers = pThisLevel->GetMembersObject();
+ long nMembCount = pMembers->getCount();
+ for ( long i=0; i<nMembCount; i++ )
+ {
+ long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];
+
+ ScDPMember* pMember = pMembers->getByIndex(nSorted);
+ if ( aCompare.IsIncluded( *pMember ) )
+ {
+ ScDPResultMember* pNew = new ScDPResultMember( pResultData, pThisDim,
+ pThisLevel, pMember, FALSE );
+ maMemberArray.push_back( pNew );
+
+ ScDPItemData aMemberData;
+ pMember->FillItemData( aMemberData );
+
+ // honour order of maMemberArray and only insert if it does not
+ // already exist
+ if ( maMemberHash.end() == maMemberHash.find( aMemberData ) )
+ maMemberHash.insert( std::pair< const ScDPItemData, ScDPResultMember *>( aMemberData, pNew ) );
+
+ rInitState.AddMember( nDimSource, aMemberData );
+ pNew->InitFrom( ppDim, ppLev, nPos+1, rInitState );
+ rInitState.RemoveMember();
+ }
+ }
+ bInitialized = TRUE;
+}
+
+void ScDPResultDimension::LateInitFrom( const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLev,
+ const vector<ScDPItemData>& pItemData, size_t nPos,
+ ScDPInitState& rInitState )
+{
+ if (nPos >= ppDim.size() || nPos >= ppLev.size() || nPos >= pItemData.size())
+ return;
+
+ ScDPDimension* pThisDim = ppDim[nPos];
+ ScDPLevel* pThisLevel = ppLev[nPos];
+ const ScDPItemData& rThisData = pItemData[nPos];
+
+ if (!pThisDim || !pThisLevel)
+ return;
+
+ long nDimSource = pThisDim->GetDimension(); //! check GetSourceDim?
+
+ if ( !bInitialized )
+ {
+ // create all members at the first call (preserve order)
+
+ bIsDataLayout = pThisDim->getIsDataLayoutDimension();
+ aDimensionName = pThisDim->getName();
+
+ const sheet::DataPilotFieldAutoShowInfo& rAutoInfo = pThisLevel->GetAutoShow();
+ if ( rAutoInfo.IsEnabled )
+ {
+ bAutoShow = TRUE;
+ bAutoTopItems = ( rAutoInfo.ShowItemsMode == sheet::DataPilotFieldShowItemsMode::FROM_TOP );
+ nAutoMeasure = pThisLevel->GetAutoMeasure();
+ nAutoCount = rAutoInfo.ItemCount;
+ }
+
+ const sheet::DataPilotFieldSortInfo& rSortInfo = pThisLevel->GetSortInfo();
+ if ( rSortInfo.Mode == sheet::DataPilotFieldSortMode::DATA )
+ {
+ bSortByData = TRUE;
+ bSortAscending = rSortInfo.IsAscending;
+ nSortMeasure = pThisLevel->GetSortMeasure();
+ }
+
+ // global order is used to initialize aMembers, so it doesn't have to be looked at later
+ const ScMemberSortOrder& rGlobalOrder = pThisLevel->GetGlobalOrder();
+
+ ScDPGroupCompare aCompare( pResultData, rInitState, nDimSource );
+
+ ScDPMembers* pMembers = pThisLevel->GetMembersObject();
+ long nMembCount = pMembers->getCount();
+ for ( long i=0; i<nMembCount; i++ )
+ {
+ long nSorted = rGlobalOrder.empty() ? i : rGlobalOrder[i];
+
+ ScDPMember* pMember = pMembers->getByIndex(nSorted);
+ if ( aCompare.IsIncluded( *pMember ) )
+ {
+ ScDPResultMember* pNew = new ScDPResultMember( pResultData, pThisDim,
+ pThisLevel, pMember, FALSE );
+ maMemberArray.push_back( pNew );
+
+ ScDPItemData aMemberData;
+ pMember->FillItemData( aMemberData );
+
+ // honour order of maMemberArray and only insert if it does not
+ // already exist
+ if ( maMemberHash.end() == maMemberHash.find( aMemberData ) )
+ maMemberHash.insert( std::pair< const ScDPItemData, ScDPResultMember *>( aMemberData, pNew ) );
+ }
+ }
+ bInitialized = TRUE; // don't call again, even if no members were included
+ }
+
+ // initialize only specific member (or all if "show empty" flag is set)
+
+ BOOL bShowEmpty = pThisLevel->getShowEmpty();
+ if ( bIsDataLayout || bShowEmpty )
+ {
+ long nCount = maMemberArray.size();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPResultMember* pResultMember = maMemberArray[i];
+ ScDPItemData aMemberData;
+ pResultMember->FillItemData( aMemberData );
+ rInitState.AddMember( nDimSource, aMemberData );
+ pResultMember->LateInitFrom( ppDim, ppLev, pItemData, nPos+1, rInitState );
+ rInitState.RemoveMember();
+ }
+ }
+ else
+ {
+ ScDPResultMember* pResultMember = FindMember( rThisData );
+ if( NULL != pResultMember )
+ {
+ ScDPItemData aMemberData;
+ pResultMember->FillItemData( aMemberData );
+ rInitState.AddMember( nDimSource, aMemberData );
+ pResultMember->LateInitFrom( ppDim, ppLev, pItemData, nPos+1, rInitState );
+ rInitState.RemoveMember();
+ }
+ }
+}
+
+long ScDPResultDimension::GetSize(long nMeasure) const
+{
+ long nTotal = 0;
+ long nMemberCount = maMemberArray.size();
+ if (bIsDataLayout)
+ {
+ DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
+ "DataLayout dimension twice?");
+ // repeat first member...
+ nTotal = nMemberCount * maMemberArray[0]->GetSize(0); // all measures have equal size
+ }
+ else
+ {
+ // add all members
+ for (long nMem=0; nMem<nMemberCount; nMem++)
+ nTotal += maMemberArray[nMem]->GetSize(nMeasure);
+ }
+ return nTotal;
+}
+
+bool ScDPResultDimension::IsValidEntry( const vector<ScDPItemData>& aMembers ) const
+{
+ if (aMembers.empty())
+ return false;
+
+ const ScDPResultMember* pMember = FindMember( aMembers[0] );
+ if ( NULL != pMember )
+ return pMember->IsValidEntry( aMembers );
+
+ DBG_ERROR("IsValidEntry: Member not found");
+ return false;
+}
+
+void ScDPResultDimension::ProcessData( const vector<ScDPItemData>& aMembers,
+ const ScDPResultDimension* pDataDim,
+ const vector<ScDPItemData>& aDataMembers,
+ const vector<ScDPValueData>& aValues ) const
+{
+ if (aMembers.empty())
+ return;
+
+ ScDPResultMember* pMember = FindMember( aMembers[0] );
+ if ( NULL != pMember )
+ {
+ vector<ScDPItemData> aChildMembers;
+ if (aMembers.size() > 1)
+ {
+ vector<ScDPItemData>::const_iterator itr = aMembers.begin();
+ aChildMembers.assign(++itr, aMembers.end());
+ }
+ pMember->ProcessData( aChildMembers, pDataDim, aDataMembers, aValues );
+ return;
+ }
+
+ DBG_ERROR("ProcessData: Member not found");
+}
+
+void ScDPResultDimension::FillMemberResults( uno::Sequence<sheet::MemberResult>* pSequences,
+ long nStart, long nMeasure )
+{
+ long nPos = nStart;
+ long nCount = maMemberArray.size();
+
+ for (long i=0; i<nCount; i++)
+ {
+ long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];
+
+ ScDPResultMember* pMember = maMemberArray[nSorted];
+ // in data layout dimension, use first member with different measures/names
+ if ( bIsDataLayout )
+ {
+ String aMbrName = pResultData->GetMeasureDimensionName( nSorted );
+ String aMbrCapt = pResultData->GetMeasureString( nSorted, FALSE, SUBTOTAL_FUNC_NONE );
+ maMemberArray[0]->FillMemberResults( pSequences, nPos, nSorted, FALSE, &aMbrName, &aMbrCapt );
+ }
+ else if ( pMember->IsVisible() )
+ pMember->FillMemberResults( pSequences, nPos, nMeasure, FALSE, NULL, NULL );
+ // nPos is modified
+ }
+}
+
+void ScDPResultDimension::FillDataResults( const ScDPResultMember* pRefMember,
+ uno::Sequence< uno::Sequence<sheet::DataResult> >& rSequence,
+ long nRow, long nMeasure ) const
+{
+ long nMemberRow = nRow;
+ long nMemberMeasure = nMeasure;
+ long nCount = maMemberArray.size();
+ for (long i=0; i<nCount; i++)
+ {
+ long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];
+
+ const ScDPResultMember* pMember;
+ if (bIsDataLayout)
+ {
+ DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
+ "DataLayout dimension twice?");
+ pMember = maMemberArray[0];
+ nMemberMeasure = nSorted;
+ }
+ else
+ pMember = maMemberArray[nSorted];
+
+ if ( pMember->IsVisible() )
+ pMember->FillDataResults( pRefMember, rSequence, nMemberRow, nMemberMeasure );
+ // nMemberRow is modified
+ }
+}
+
+void ScDPResultDimension::UpdateDataResults( const ScDPResultMember* pRefMember, long nMeasure ) const
+{
+ long nMemberMeasure = nMeasure;
+ long nCount = maMemberArray.size();
+ for (long i=0; i<nCount; i++)
+ {
+ const ScDPResultMember* pMember;
+ if (bIsDataLayout)
+ {
+ DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
+ "DataLayout dimension twice?");
+ pMember = maMemberArray[0];
+ nMemberMeasure = i;
+ }
+ else
+ pMember = maMemberArray[i];
+
+ if ( pMember->IsVisible() )
+ pMember->UpdateDataResults( pRefMember, nMemberMeasure );
+ }
+}
+
+void ScDPResultDimension::SortMembers( ScDPResultMember* pRefMember )
+{
+ long nCount = maMemberArray.size();
+
+ if ( bSortByData )
+ {
+ // sort members
+
+ DBG_ASSERT( aMemberOrder.empty(), "sort twice?" );
+ aMemberOrder.resize( nCount );
+ for (long nPos=0; nPos<nCount; nPos++)
+ aMemberOrder[nPos] = nPos;
+
+ ScDPRowMembersOrder aComp( *this, nSortMeasure, bSortAscending );
+ ::std::sort( aMemberOrder.begin(), aMemberOrder.end(), aComp );
+ }
+
+ // handle children
+
+ // for data layout, call only once - sorting measure is always taken from settings
+ long nLoopCount = bIsDataLayout ? 1 : nCount;
+ for (long i=0; i<nLoopCount; i++)
+ {
+ ScDPResultMember* pMember = maMemberArray[i];
+ if ( pMember->IsVisible() )
+ pMember->SortMembers( pRefMember );
+ }
+}
+
+void ScDPResultDimension::DoAutoShow( ScDPResultMember* pRefMember )
+{
+ long nCount = maMemberArray.size();
+
+ // handle children first, before changing the visible state
+
+ // for data layout, call only once - sorting measure is always taken from settings
+ long nLoopCount = bIsDataLayout ? 1 : nCount;
+ for (long i=0; i<nLoopCount; i++)
+ {
+ ScDPResultMember* pMember = maMemberArray[i];
+ if ( pMember->IsVisible() )
+ pMember->DoAutoShow( pRefMember );
+ }
+
+ if ( bAutoShow && nAutoCount > 0 && nAutoCount < nCount )
+ {
+ // establish temporary order, hide remaining members
+
+ ScMemberSortOrder aAutoOrder;
+ aAutoOrder.resize( nCount );
+ long nPos;
+ for (nPos=0; nPos<nCount; nPos++)
+ aAutoOrder[nPos] = nPos;
+
+ ScDPRowMembersOrder aComp( *this, nAutoMeasure, !bAutoTopItems );
+ ::std::sort( aAutoOrder.begin(), aAutoOrder.end(), aComp );
+
+ // look for equal values to the last included one
+
+ long nIncluded = nAutoCount;
+ const ScDPResultMember* pMember1 = maMemberArray[aAutoOrder[nIncluded - 1]];
+ const ScDPDataMember* pDataMember1 = pMember1->IsVisible() ? pMember1->GetDataRoot() : NULL;
+ BOOL bContinue = TRUE;
+ while ( bContinue )
+ {
+ bContinue = FALSE;
+ if ( nIncluded < nCount )
+ {
+ const ScDPResultMember* pMember2 = maMemberArray[aAutoOrder[nIncluded]];
+ const ScDPDataMember* pDataMember2 = pMember2->IsVisible() ? pMember2->GetDataRoot() : NULL;
+
+ if ( lcl_IsEqual( pDataMember1, pDataMember2, nAutoMeasure ) )
+ {
+ ++nIncluded; // include more members if values are equal
+ bContinue = TRUE;
+ }
+ }
+ }
+
+ // hide the remaining members
+
+ for (nPos = nIncluded; nPos < nCount; nPos++)
+ {
+ ScDPResultMember* pMember = maMemberArray[aAutoOrder[nPos]];
+ pMember->SetAutoHidden();
+ }
+ }
+}
+
+void ScDPResultDimension::ResetResults()
+{
+ long nCount = maMemberArray.size();
+ for (long i=0; i<nCount; i++)
+ {
+ // sort order doesn't matter
+ ScDPResultMember* pMember = maMemberArray[bIsDataLayout ? 0 : i];
+ pMember->ResetResults( FALSE );
+ }
+}
+
+long ScDPResultDimension::GetSortedIndex( long nUnsorted ) const
+{
+ return aMemberOrder.empty() ? nUnsorted : aMemberOrder[nUnsorted];
+}
+
+void ScDPResultDimension::UpdateRunningTotals( const ScDPResultMember* pRefMember, long nMeasure,
+ ScDPRunningTotalState& rRunning, ScDPRowTotals& rTotals ) const
+{
+ const ScDPResultMember* pMember;
+ long nMemberMeasure = nMeasure;
+ long nCount = maMemberArray.size();
+ for (long i=0; i<nCount; i++)
+ {
+ long nSorted = aMemberOrder.empty() ? i : aMemberOrder[i];
+
+ if (bIsDataLayout)
+ {
+ DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
+ "DataLayout dimension twice?");
+ pMember = maMemberArray[0];
+ nMemberMeasure = nSorted;
+ }
+ else
+ pMember = maMemberArray[nSorted];
+
+ if ( pMember->IsVisible() )
+ {
+ if ( bIsDataLayout )
+ rRunning.AddRowIndex( 0, 0 );
+ else
+ rRunning.AddRowIndex( i, nSorted );
+ pMember->UpdateRunningTotals( pRefMember, nMemberMeasure, rRunning, rTotals );
+ rRunning.RemoveRowIndex();
+ }
+ }
+}
+
+ScDPDataMember* ScDPResultDimension::GetRowReferenceMember( const ScDPRelativePos* pRelativePos, const String* pName,
+ const long* pRowIndexes, const long* pColIndexes ) const
+{
+ // get named, previous/next, or first member of this dimension (first existing if pRelativePos and pName are NULL)
+
+ DBG_ASSERT( pRelativePos == NULL || pName == NULL, "can't use position and name" );
+
+ ScDPDataMember* pColMember = NULL;
+
+ BOOL bFirstExisting = ( pRelativePos == NULL && pName == NULL );
+ long nMemberCount = maMemberArray.size();
+ long nMemberIndex = 0; // unsorted
+ long nDirection = 1; // forward if no relative position is used
+ if ( pRelativePos )
+ {
+ nDirection = pRelativePos->nDirection;
+ nMemberIndex = pRelativePos->nBasePos + nDirection; // bounds are handled below
+
+ DBG_ASSERT( nDirection == 1 || nDirection == -1, "Direction must be 1 or -1" );
+ }
+ else if ( pName )
+ {
+ // search for named member
+
+ const ScDPResultMember* pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)];
+
+ //! use ScDPItemData, as in ScDPDimension::IsValidPage?
+ while ( pRowMember && pRowMember->GetName() != *pName )
+ {
+ ++nMemberIndex;
+ if ( nMemberIndex < nMemberCount )
+ pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)];
+ else
+ pRowMember = NULL;
+ }
+ }
+
+ BOOL bContinue = TRUE;
+ while ( bContinue && nMemberIndex >= 0 && nMemberIndex < nMemberCount )
+ {
+ const ScDPResultMember* pRowMember = maMemberArray[GetSortedIndex(nMemberIndex)];
+
+ // get child members by given indexes
+
+ const long* pNextRowIndex = pRowIndexes;
+ while ( *pNextRowIndex >= 0 && pRowMember )
+ {
+ const ScDPResultDimension* pRowChild = pRowMember->GetChildDimension();
+ if ( pRowChild && *pNextRowIndex < pRowChild->GetMemberCount() )
+ pRowMember = pRowChild->GetMember( *pNextRowIndex );
+ else
+ pRowMember = NULL;
+ ++pNextRowIndex;
+ }
+
+ if ( pRowMember && pRelativePos )
+ {
+ // Skip the member if it has hidden details
+ // (because when looking for the details, it is skipped, too).
+ // Also skip if the member is invisible because it has no data,
+ // for consistent ordering.
+ if ( pRowMember->HasHiddenDetails() || !pRowMember->IsVisible() )
+ pRowMember = NULL;
+ }
+
+ if ( pRowMember )
+ {
+ pColMember = pRowMember->GetDataRoot();
+
+ const long* pNextColIndex = pColIndexes;
+ while ( *pNextColIndex >= 0 && pColMember )
+ {
+ const ScDPDataDimension* pColChild = pColMember->GetChildDimension();
+ if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
+ pColMember = pColChild->GetMember( *pNextColIndex );
+ else
+ pColMember = NULL;
+ ++pNextColIndex;
+ }
+ }
+
+ // continue searching only if looking for first existing or relative position
+ bContinue = ( pColMember == NULL && ( bFirstExisting || pRelativePos ) );
+ nMemberIndex += nDirection;
+ }
+
+ return pColMember;
+}
+
+// static
+ScDPDataMember* ScDPResultDimension::GetColReferenceMember( const ScDPRelativePos* pRelativePos, const String* pName,
+ long nRefDimPos, const ScDPRunningTotalState& rRunning )
+{
+ DBG_ASSERT( pRelativePos == NULL || pName == NULL, "can't use position and name" );
+
+ const long* pColIndexes = rRunning.GetColIndexes();
+ const long* pRowIndexes = rRunning.GetRowIndexes();
+
+ // get own row member using all indexes
+
+ const ScDPResultMember* pRowMember = rRunning.GetRowResRoot();
+ ScDPDataMember* pColMember = NULL;
+
+ const long* pNextRowIndex = pRowIndexes;
+ while ( *pNextRowIndex >= 0 && pRowMember )
+ {
+ const ScDPResultDimension* pRowChild = pRowMember->GetChildDimension();
+ if ( pRowChild && *pNextRowIndex < pRowChild->GetMemberCount() )
+ pRowMember = pRowChild->GetMember( *pNextRowIndex );
+ else
+ pRowMember = NULL;
+ ++pNextRowIndex;
+ }
+
+ // get column (data) members before the reference field
+ //! pass rRowParent from ScDPDataMember::UpdateRunningTotals instead
+
+ if ( pRowMember )
+ {
+ pColMember = pRowMember->GetDataRoot();
+
+ const long* pNextColIndex = pColIndexes;
+ long nColSkipped = 0;
+ while ( *pNextColIndex >= 0 && pColMember && nColSkipped < nRefDimPos )
+ {
+ const ScDPDataDimension* pColChild = pColMember->GetChildDimension();
+ if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
+ pColMember = pColChild->GetMember( *pNextColIndex );
+ else
+ pColMember = NULL;
+ ++pNextColIndex;
+ ++nColSkipped;
+ }
+ }
+
+ // get column member for the reference field
+
+ if ( pColMember )
+ {
+ const ScDPDataDimension* pReferenceDim = pColMember->GetChildDimension();
+ if ( pReferenceDim )
+ {
+ long nReferenceCount = pReferenceDim->GetMemberCount();
+
+ BOOL bFirstExisting = ( pRelativePos == NULL && pName == NULL );
+ long nMemberIndex = 0; // unsorted
+ long nDirection = 1; // forward if no relative position is used
+ pColMember = NULL; // don't use parent dimension's member if none found
+ if ( pRelativePos )
+ {
+ nDirection = pRelativePos->nDirection;
+ nMemberIndex = pRelativePos->nBasePos + nDirection; // bounds are handled below
+ }
+ else if ( pName )
+ {
+ // search for named member
+
+ pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );
+
+ //! use ScDPItemData, as in ScDPDimension::IsValidPage?
+ while ( pColMember && pColMember->GetName() != *pName )
+ {
+ ++nMemberIndex;
+ if ( nMemberIndex < nReferenceCount )
+ pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );
+ else
+ pColMember = NULL;
+ }
+ }
+
+ BOOL bContinue = TRUE;
+ while ( bContinue && nMemberIndex >= 0 && nMemberIndex < nReferenceCount )
+ {
+ pColMember = pReferenceDim->GetMember( pReferenceDim->GetSortedIndex( nMemberIndex ) );
+
+ // get column members below the reference field
+
+ const long* pNextColIndex = pColIndexes + nRefDimPos + 1;
+ while ( *pNextColIndex >= 0 && pColMember )
+ {
+ const ScDPDataDimension* pColChild = pColMember->GetChildDimension();
+ if ( pColChild && *pNextColIndex < pColChild->GetMemberCount() )
+ pColMember = pColChild->GetMember( *pNextColIndex );
+ else
+ pColMember = NULL;
+ ++pNextColIndex;
+ }
+
+ if ( pColMember && pRelativePos )
+ {
+ // Skip the member if it has hidden details
+ // (because when looking for the details, it is skipped, too).
+ // Also skip if the member is invisible because it has no data,
+ // for consistent ordering.
+ if ( pColMember->HasHiddenDetails() || !pColMember->IsVisible() )
+ pColMember = NULL;
+ }
+
+ // continue searching only if looking for first existing or relative position
+ bContinue = ( pColMember == NULL && ( bFirstExisting || pRelativePos ) );
+ nMemberIndex += nDirection;
+ }
+ }
+ else
+ pColMember = NULL;
+ }
+
+ return pColMember;
+}
+
+void ScDPResultDimension::DumpState( const ScDPResultMember* pRefMember, ScDocument* pDoc, ScAddress& rPos ) const
+{
+ String aDimName = bIsDataLayout ? String::CreateFromAscii("(data layout)") : GetName();
+ lcl_DumpRow( String::CreateFromAscii("ScDPResultDimension"), aDimName, NULL, pDoc, rPos );
+
+ SCROW nStartRow = rPos.Row();
+
+ long nCount = bIsDataLayout ? 1 : maMemberArray.size();
+ for (long i=0; i<nCount; i++)
+ {
+ const ScDPResultMember* pMember = maMemberArray[i];
+ pMember->DumpState( pRefMember, pDoc, rPos );
+ }
+
+ lcl_Indent( pDoc, nStartRow, rPos );
+}
+
+long ScDPResultDimension::GetMemberCount() const
+{
+ return maMemberArray.size();
+}
+
+const ScDPResultMember* ScDPResultDimension::GetMember(long n) const
+{
+ return maMemberArray[n];
+}
+ScDPResultMember* ScDPResultDimension::GetMember(long n)
+{
+ return maMemberArray[n];
+}
+
+ScDPResultDimension* ScDPResultDimension::GetFirstChildDimension() const
+{
+ if ( maMemberArray.size() > 0 )
+ return maMemberArray[0]->GetChildDimension();
+ else
+ return NULL;
+}
+
+void ScDPResultDimension::FillVisibilityData(ScDPResultVisibilityData& rData) const
+{
+ if (IsDataLayout())
+ return;
+
+ MemberArray::const_iterator itr = maMemberArray.begin(), itrEnd = maMemberArray.end();
+
+ for (;itr != itrEnd; ++itr)
+ {
+ ScDPResultMember* pMember = *itr;
+ if (pMember->IsValid())
+ {
+ ScDPItemData aItem;
+ pMember->FillItemData(aItem);
+ rData.addVisibleMember(GetName(), aItem);
+ pMember->FillVisibilityData(rData);
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ScDPDataDimension::ScDPDataDimension( const ScDPResultData* pData ) :
+ pResultData( pData ),
+ pResultDimension( NULL ),
+ bIsDataLayout( FALSE )
+{
+}
+
+ScDPDataDimension::~ScDPDataDimension()
+{
+}
+
+void ScDPDataDimension::InitFrom( const ScDPResultDimension* pDim )
+{
+ if (!pDim)
+ return;
+
+ pResultDimension = pDim;
+ bIsDataLayout = pDim->IsDataLayout();
+
+ // Go through all result members under the given result dimension, and
+ // create a new data member instance for each result member.
+ long nCount = pDim->GetMemberCount();
+ for (long i=0; i<nCount; i++)
+ {
+ const ScDPResultMember* pResMem = pDim->GetMember(i);
+
+ ScDPDataMember* pNew = new ScDPDataMember( pResultData, pResMem );
+ aMembers.Insert( pNew, aMembers.Count() );
+
+ if ( !pResultData->IsLateInit() )
+ {
+ // with LateInit, pResMem hasn't necessarily been initialized yet,
+ // so InitFrom for the new result member is called from its ProcessData method
+
+ const ScDPResultDimension* pChildDim = pResMem->GetChildDimension();
+ if ( pChildDim )
+ pNew->InitFrom( pChildDim );
+ }
+ }
+}
+
+void ScDPDataDimension::ProcessData( const vector<ScDPItemData>& aDataMembers, const vector<ScDPValueData>& aValues,
+ const ScDPSubTotalState& rSubState )
+{
+ // the ScDPItemData array must contain enough entries for all dimensions - this isn't checked
+
+ long nCount = aMembers.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ ScDPDataMember* pMember = aMembers[(USHORT)i];
+
+ // always first member for data layout dim
+ if ( bIsDataLayout || ( !aDataMembers.empty() && pMember->IsNamedItem(aDataMembers[0]) ) )
+ {
+ vector<ScDPItemData> aChildDataMembers;
+ if (aDataMembers.size() > 1)
+ {
+ vector<ScDPItemData>::const_iterator itr = aDataMembers.begin();
+ aChildDataMembers.assign(++itr, aDataMembers.end());
+ }
+ pMember->ProcessData( aChildDataMembers, aValues, rSubState );
+ return;
+ }
+ }
+
+ DBG_ERROR("ProcessData: Member not found");
+}
+
+void ScDPDataDimension::FillDataRow( const ScDPResultDimension* pRefDim,
+ uno::Sequence<sheet::DataResult>& rSequence,
+ long nCol, long nMeasure, BOOL bIsSubTotalRow,
+ const ScDPSubTotalState& rSubState ) const
+{
+ DBG_ASSERT( pRefDim && pRefDim->GetMemberCount() == aMembers.Count(), "dimensions don't match" );
+ DBG_ASSERT( pRefDim == pResultDimension, "wrong dim" );
+
+ const ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
+
+ long nMemberMeasure = nMeasure;
+ long nMemberCol = nCol;
+ long nCount = aMembers.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ long nSorted = rMemberOrder.empty() ? i : rMemberOrder[i];
+
+ long nMemberPos = nSorted;
+ if (bIsDataLayout)
+ {
+ DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
+ "DataLayout dimension twice?");
+ nMemberPos = 0;
+ nMemberMeasure = nSorted;
+ }
+
+ const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
+ if ( pRefMember->IsVisible() ) //! here or in ScDPDataMember::FillDataRow ???
+ {
+ const ScDPDataMember* pDataMember = aMembers[(USHORT)nMemberPos];
+ pDataMember->FillDataRow( pRefMember, rSequence, nMemberCol, nMemberMeasure, bIsSubTotalRow, rSubState );
+ // nMemberCol is modified
+ }
+ }
+}
+
+void ScDPDataDimension::UpdateDataRow( const ScDPResultDimension* pRefDim,
+ long nMeasure, BOOL bIsSubTotalRow,
+ const ScDPSubTotalState& rSubState ) const
+{
+ DBG_ASSERT( pRefDim && pRefDim->GetMemberCount() == aMembers.Count(), "dimensions don't match" );
+ DBG_ASSERT( pRefDim == pResultDimension, "wrong dim" );
+
+ long nMemberMeasure = nMeasure;
+ long nCount = aMembers.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ long nMemberPos = i;
+ if (bIsDataLayout)
+ {
+ DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
+ "DataLayout dimension twice?");
+ nMemberPos = 0;
+ nMemberMeasure = i;
+ }
+
+ // Calculate must be called even if the member is not visible (for use as reference value)
+ const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
+ ScDPDataMember* pDataMember = aMembers[(USHORT)nMemberPos];
+ pDataMember->UpdateDataRow( pRefMember, nMemberMeasure, bIsSubTotalRow, rSubState );
+ }
+}
+
+void ScDPDataDimension::SortMembers( ScDPResultDimension* pRefDim )
+{
+ long nCount = aMembers.Count();
+
+ if ( pRefDim->IsSortByData() )
+ {
+ // sort members
+
+ ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
+ DBG_ASSERT( rMemberOrder.empty(), "sort twice?" );
+ rMemberOrder.resize( nCount );
+ for (long nPos=0; nPos<nCount; nPos++)
+ rMemberOrder[nPos] = nPos;
+
+ ScDPColMembersOrder aComp( *this, pRefDim->GetSortMeasure(), pRefDim->IsSortAscending() );
+ ::std::sort( rMemberOrder.begin(), rMemberOrder.end(), aComp );
+ }
+
+ // handle children
+
+ DBG_ASSERT( pRefDim && pRefDim->GetMemberCount() == aMembers.Count(), "dimensions don't match" );
+ DBG_ASSERT( pRefDim == pResultDimension, "wrong dim" );
+
+ // for data layout, call only once - sorting measure is always taken from settings
+ long nLoopCount = bIsDataLayout ? 1 : nCount;
+ for (long i=0; i<nLoopCount; i++)
+ {
+ ScDPResultMember* pRefMember = pRefDim->GetMember(i);
+ if ( pRefMember->IsVisible() ) //! here or in ScDPDataMember ???
+ {
+ ScDPDataMember* pDataMember = aMembers[(USHORT)i];
+ pDataMember->SortMembers( pRefMember );
+ }
+ }
+}
+
+void ScDPDataDimension::DoAutoShow( ScDPResultDimension* pRefDim )
+{
+ long nCount = aMembers.Count();
+
+ // handle children first, before changing the visible state
+
+ DBG_ASSERT( pRefDim && pRefDim->GetMemberCount() == aMembers.Count(), "dimensions don't match" );
+ DBG_ASSERT( pRefDim == pResultDimension, "wrong dim" );
+
+ // for data layout, call only once - sorting measure is always taken from settings
+ long nLoopCount = bIsDataLayout ? 1 : nCount;
+ for (long i=0; i<nLoopCount; i++)
+ {
+ ScDPResultMember* pRefMember = pRefDim->GetMember(i);
+ if ( pRefMember->IsVisible() ) //! here or in ScDPDataMember ???
+ {
+ ScDPDataMember* pDataMember = aMembers[(USHORT)i];
+ pDataMember->DoAutoShow( pRefMember );
+ }
+ }
+
+ if ( pRefDim->IsAutoShow() && pRefDim->GetAutoCount() > 0 && pRefDim->GetAutoCount() < nCount )
+ {
+ // establish temporary order, hide remaining members
+
+ ScMemberSortOrder aAutoOrder;
+ aAutoOrder.resize( nCount );
+ long nPos;
+ for (nPos=0; nPos<nCount; nPos++)
+ aAutoOrder[nPos] = nPos;
+
+ ScDPColMembersOrder aComp( *this, pRefDim->GetAutoMeasure(), !pRefDim->IsAutoTopItems() );
+ ::std::sort( aAutoOrder.begin(), aAutoOrder.end(), aComp );
+
+ // look for equal values to the last included one
+
+ long nIncluded = pRefDim->GetAutoCount();
+ ScDPDataMember* pDataMember1 = aMembers[(USHORT)aAutoOrder[nIncluded - 1]];
+ if ( !pDataMember1->IsVisible() )
+ pDataMember1 = NULL;
+ BOOL bContinue = TRUE;
+ while ( bContinue )
+ {
+ bContinue = FALSE;
+ if ( nIncluded < nCount )
+ {
+ ScDPDataMember* pDataMember2 = aMembers[(USHORT)aAutoOrder[nIncluded]];
+ if ( !pDataMember2->IsVisible() )
+ pDataMember2 = NULL;
+
+ if ( lcl_IsEqual( pDataMember1, pDataMember2, pRefDim->GetAutoMeasure() ) )
+ {
+ ++nIncluded; // include more members if values are equal
+ bContinue = TRUE;
+ }
+ }
+ }
+
+ // hide the remaining members
+
+ for (nPos = nIncluded; nPos < nCount; nPos++)
+ {
+ ScDPResultMember* pMember = pRefDim->GetMember(aAutoOrder[nPos]);
+ pMember->SetAutoHidden();
+ }
+ }
+}
+
+void ScDPDataDimension::ResetResults()
+{
+ long nCount = aMembers.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ // sort order doesn't matter
+
+ long nMemberPos = bIsDataLayout ? 0 : i;
+ ScDPDataMember* pDataMember = aMembers[(USHORT)nMemberPos];
+ pDataMember->ResetResults();
+ }
+}
+
+long ScDPDataDimension::GetSortedIndex( long nUnsorted ) const
+{
+ if (!pResultDimension)
+ return nUnsorted;
+
+ const ScMemberSortOrder& rMemberOrder = pResultDimension->GetMemberOrder();
+ return rMemberOrder.empty() ? nUnsorted : rMemberOrder[nUnsorted];
+}
+
+void ScDPDataDimension::UpdateRunningTotals( const ScDPResultDimension* pRefDim,
+ long nMeasure, BOOL bIsSubTotalRow,
+ const ScDPSubTotalState& rSubState, ScDPRunningTotalState& rRunning,
+ ScDPRowTotals& rTotals, const ScDPResultMember& rRowParent ) const
+{
+ DBG_ASSERT( pRefDim && pRefDim->GetMemberCount() == aMembers.Count(), "dimensions don't match" );
+ DBG_ASSERT( pRefDim == pResultDimension, "wrong dim" );
+
+ long nMemberMeasure = nMeasure;
+ long nCount = aMembers.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ const ScMemberSortOrder& rMemberOrder = pRefDim->GetMemberOrder();
+ long nSorted = rMemberOrder.empty() ? i : rMemberOrder[i];
+
+ long nMemberPos = nSorted;
+ if (bIsDataLayout)
+ {
+ DBG_ASSERT(nMeasure == SC_DPMEASURE_ALL || pResultData->GetMeasureCount() == 1,
+ "DataLayout dimension twice?");
+ nMemberPos = 0;
+ nMemberMeasure = nSorted;
+ }
+
+ const ScDPResultMember* pRefMember = pRefDim->GetMember(nMemberPos);
+ if ( pRefMember->IsVisible() ) //! here or in ScDPDataMember::UpdateRunningTotals ???
+ {
+ if ( bIsDataLayout )
+ rRunning.AddColIndex( 0, 0 );
+ else
+ rRunning.AddColIndex( i, nSorted );
+
+ ScDPDataMember* pDataMember = aMembers[(USHORT)nMemberPos];
+ pDataMember->UpdateRunningTotals( pRefMember, nMemberMeasure,
+ bIsSubTotalRow, rSubState, rRunning, rTotals, rRowParent );
+
+ rRunning.RemoveColIndex();
+ }
+ }
+}
+
+void ScDPDataDimension::DumpState( const ScDPResultDimension* pRefDim, ScDocument* pDoc, ScAddress& rPos ) const
+{
+ String aDimName = String::CreateFromAscii( bIsDataLayout ? "(data layout)" : "(unknown)" );
+ lcl_DumpRow( String::CreateFromAscii("ScDPDataDimension"), aDimName, NULL, pDoc, rPos );
+
+ SCROW nStartRow = rPos.Row();
+
+ long nCount = bIsDataLayout ? 1 : aMembers.Count();
+ for (long i=0; i<nCount; i++)
+ {
+ const ScDPResultMember* pRefMember = pRefDim->GetMember(i);
+ const ScDPDataMember* pDataMember = aMembers[(USHORT)i];
+ pDataMember->DumpState( pRefMember, pDoc, rPos );
+ }
+
+ lcl_Indent( pDoc, nStartRow, rPos );
+}
+
+long ScDPDataDimension::GetMemberCount() const
+{
+ return aMembers.Count();
+}
+
+ScDPDataMember* ScDPDataDimension::GetMember(long n) const
+{
+ return aMembers[(USHORT)n];
+}
+
+// ----------------------------------------------------------------------------
+
+ScDPResultVisibilityData::ScDPResultVisibilityData(
+ ScSimpleSharedString& rSharedString, ScDPSource* pSource) :
+ mrSharedString(rSharedString),
+ mpSource(pSource)
+{
+}
+
+ScDPResultVisibilityData::~ScDPResultVisibilityData()
+{
+}
+
+void ScDPResultVisibilityData::addVisibleMember(const String& rDimName, const ScDPItemData& rMemberItem)
+{
+ DimMemberType::iterator itr = maDimensions.find(rDimName);
+ if (itr == maDimensions.end())
+ {
+ pair<DimMemberType::iterator, bool> r = maDimensions.insert(
+ DimMemberType::value_type(rDimName, VisibleMemberType()));
+
+ if (!r.second)
+ // insertion failed.
+ return;
+
+ itr = r.first;
+ }
+ VisibleMemberType& rMem = itr->second;
+ VisibleMemberType::iterator itrMem = rMem.find(rMemberItem);
+ if (itrMem == rMem.end())
+ rMem.insert(rMemberItem);
+}
+
+void ScDPResultVisibilityData::fillFieldFilters(vector<ScDPCacheTable::Criterion>& rFilters) const
+{
+ typedef hash_map<String, long, ScStringHashCode> FieldNameMapType;
+ FieldNameMapType aFieldNames;
+ ScDPTableData* pData = mpSource->GetData();
+ long nColumnCount = pData->GetColumnCount();
+ for (long i = 0; i < nColumnCount; ++i)
+ {
+ aFieldNames.insert(
+ FieldNameMapType::value_type(pData->getDimensionName(i), i));
+ }
+
+ const ScDPDimensions* pDims = mpSource->GetDimensionsObject();
+ for (DimMemberType::const_iterator itr = maDimensions.begin(), itrEnd = maDimensions.end();
+ itr != itrEnd; ++itr)
+ {
+ const String& rDimName = itr->first;
+ ScDPCacheTable::Criterion aCri;
+ FieldNameMapType::const_iterator itrField = aFieldNames.find(rDimName);
+ if (itrField == aFieldNames.end())
+ // This should never happen!
+ continue;
+
+ long nDimIndex = itrField->second;
+ aCri.mnFieldIndex = static_cast<sal_Int32>(nDimIndex);
+ aCri.mpFilter.reset(new ScDPCacheTable::GroupFilter(mrSharedString));
+ ScDPCacheTable::GroupFilter* pGrpFilter =
+ static_cast<ScDPCacheTable::GroupFilter*>(aCri.mpFilter.get());
+
+ const VisibleMemberType& rMem = itr->second;
+ for (VisibleMemberType::const_iterator itrMem = rMem.begin(), itrMemEnd = rMem.end();
+ itrMem != itrMemEnd; ++itrMem)
+ {
+ const ScDPItemData& rMemItem = *itrMem;
+ pGrpFilter->addMatchItem(rMemItem.aString, rMemItem.fValue, rMemItem.bHasValue);
+ }
+
+ ScDPDimension* pDim = pDims->getByIndex(nDimIndex);
+ ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)->
+ GetLevelsObject()->getByIndex(0)->GetMembersObject();
+ if (pGrpFilter->getMatchItemCount() < static_cast<size_t>(pMembers->getCount()))
+ rFilters.push_back(aCri);
+ }
+}
+
+size_t ScDPResultVisibilityData::MemberHash::operator() (const ScDPItemData& r) const
+{
+ if (r.bHasValue)
+ return static_cast<size_t>(::rtl::math::approxFloor(r.fValue));
+ else
+ return rtl_ustr_hashCode_WithLength(r.aString.GetBuffer(), r.aString.Len());
+}
diff --git a/sc/source/core/data/dptabsrc.cxx b/sc/source/core/data/dptabsrc.cxx
new file mode 100644
index 000000000000..83c90a4bd946
--- /dev/null
+++ b/sc/source/core/data/dptabsrc.cxx
@@ -0,0 +1,2725 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: dptabsrc.cxx,v $
+ * $Revision: 1.27 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <algorithm>
+#include <vector>
+#include <set>
+#include <hash_map>
+#include <hash_set>
+
+#include <tools/debug.hxx>
+#include <rtl/math.hxx>
+#include <svtools/itemprop.hxx>
+#include <svtools/intitem.hxx>
+
+#include "scitems.hxx"
+#include "document.hxx"
+#include "docpool.hxx"
+#include "patattr.hxx"
+#include "cell.hxx"
+
+#include "dptabsrc.hxx"
+#include "dptabres.hxx"
+#include "dptabdat.hxx"
+#include "global.hxx"
+#include "collect.hxx"
+#include "datauno.hxx" // ScDataUnoConversion
+#include "unoguard.hxx"
+#include "miscuno.hxx"
+#include "unonames.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
+#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
+#include <com/sun/star/sheet/DataPilotFieldAutoShowInfo.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+
+#include <unotools/collatorwrapper.hxx>
+#include <unotools/calendarwrapper.hxx>
+#include <com/sun/star/i18n/CalendarDisplayIndex.hpp>
+
+using namespace com::sun::star;
+using ::std::vector;
+using ::std::set;
+using ::std::hash_map;
+using ::std::hash_set;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::sheet::DataPilotFieldAutoShowInfo;
+
+// -----------------------------------------------------------------------
+
+#define SC_MINCOUNT_LIMIT 1000000
+
+// -----------------------------------------------------------------------
+
+SC_SIMPLE_SERVICE_INFO( ScDPSource, "ScDPSource", "com.sun.star.sheet.DataPilotSource" )
+SC_SIMPLE_SERVICE_INFO( ScDPDimensions, "ScDPDimensions", "com.sun.star.sheet.DataPilotSourceDimensions" )
+SC_SIMPLE_SERVICE_INFO( ScDPDimension, "ScDPDimension", "com.sun.star.sheet.DataPilotSourceDimension" )
+SC_SIMPLE_SERVICE_INFO( ScDPHierarchies, "ScDPHierarchies", "com.sun.star.sheet.DataPilotSourceHierarcies" )
+SC_SIMPLE_SERVICE_INFO( ScDPHierarchy, "ScDPHierarchy", "com.sun.star.sheet.DataPilotSourceHierarcy" )
+SC_SIMPLE_SERVICE_INFO( ScDPLevels, "ScDPLevels", "com.sun.star.sheet.DataPilotSourceLevels" )
+SC_SIMPLE_SERVICE_INFO( ScDPLevel, "ScDPLevel", "com.sun.star.sheet.DataPilotSourceLevel" )
+SC_SIMPLE_SERVICE_INFO( ScDPMembers, "ScDPMembers", "com.sun.star.sheet.DataPilotSourceMembers" )
+SC_SIMPLE_SERVICE_INFO( ScDPMember, "ScDPMember", "com.sun.star.sheet.DataPilotSourceMember" )
+
+// -----------------------------------------------------------------------
+
+// property maps for PropertySetInfo
+// DataDescription / NumberFormat are internal
+
+// -----------------------------------------------------------------------
+
+//! move to a header?
+BOOL lcl_GetBoolFromAny( const uno::Any& aAny )
+{
+ if ( aAny.getValueTypeClass() == uno::TypeClass_BOOLEAN )
+ return *(sal_Bool*)aAny.getValue();
+ return FALSE;
+}
+
+void lcl_SetBoolInAny( uno::Any& rAny, BOOL bValue )
+{
+ rAny.setValue( &bValue, getBooleanCppuType() );
+}
+
+// -----------------------------------------------------------------------
+
+ScDPSource::ScDPSource( ScDPTableData* pD ) :
+ pData( pD ),
+ pDimensions( NULL ),
+ nColDimCount( 0 ),
+ nRowDimCount( 0 ),
+ nDataDimCount( 0 ),
+ nPageDimCount( 0 ),
+ bColumnGrand( TRUE ), // default is true
+ bRowGrand( TRUE ),
+ bIgnoreEmptyRows( FALSE ),
+ bRepeatIfEmpty( FALSE ),
+ nDupCount( 0 ),
+ pResData( NULL ),
+ pColResRoot( NULL ),
+ pRowResRoot( NULL ),
+ pColResults( NULL ),
+ pRowResults( NULL ),
+ bResultOverflow( FALSE )
+{
+ pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
+}
+
+ScDPSource::~ScDPSource()
+{
+ delete pData; // ScDPTableData is not ref-counted
+
+ if (pDimensions)
+ pDimensions->release(); // ref-counted
+
+ //! free lists
+
+ delete[] pColResults;
+ delete[] pRowResults;
+
+ delete pColResRoot;
+ delete pRowResRoot;
+ delete pResData;
+}
+
+USHORT ScDPSource::GetOrientation(long nColumn)
+{
+ long i;
+ for (i=0; i<nColDimCount; i++)
+ if (nColDims[i] == nColumn)
+ return sheet::DataPilotFieldOrientation_COLUMN;
+ for (i=0; i<nRowDimCount; i++)
+ if (nRowDims[i] == nColumn)
+ return sheet::DataPilotFieldOrientation_ROW;
+ for (i=0; i<nDataDimCount; i++)
+ if (nDataDims[i] == nColumn)
+ return sheet::DataPilotFieldOrientation_DATA;
+ for (i=0; i<nPageDimCount; i++)
+ if (nPageDims[i] == nColumn)
+ return sheet::DataPilotFieldOrientation_PAGE;
+ return sheet::DataPilotFieldOrientation_HIDDEN;
+}
+
+long ScDPSource::GetDataDimensionCount()
+{
+ return nDataDimCount;
+}
+
+String ScDPSource::GetDataDimName( long nIndex )
+{
+ String aRet;
+ if ( nIndex >= 0 && nIndex < nDataDimCount )
+ {
+ long nDimIndex = nDataDims[nIndex];
+ ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nDimIndex);
+ if (pDim)
+ aRet = String( pDim->getName() );
+ }
+ return aRet;
+}
+
+long ScDPSource::GetPosition(long nColumn)
+{
+ long i;
+ for (i=0; i<nColDimCount; i++)
+ if (nColDims[i] == nColumn)
+ return i;
+ for (i=0; i<nRowDimCount; i++)
+ if (nRowDims[i] == nColumn)
+ return i;
+ for (i=0; i<nDataDimCount; i++)
+ if (nDataDims[i] == nColumn)
+ return i;
+ for (i=0; i<nPageDimCount; i++)
+ if (nPageDims[i] == nColumn)
+ return i;
+ return 0;
+}
+
+BOOL lcl_TestSubTotal( BOOL& rAllowed, long nColumn, long* pArray, long nCount, ScDPSource* pSource )
+{
+ for (long i=0; i<nCount; i++)
+ if (pArray[i] == nColumn)
+ {
+ // no subtotals for data layout dim, no matter where
+ if ( pSource->IsDataLayoutDimension(nColumn) )
+ rAllowed = FALSE;
+ else
+ {
+ // no subtotals if no other dim but data layout follows
+ long nNextIndex = i+1;
+ if ( nNextIndex < nCount && pSource->IsDataLayoutDimension(pArray[nNextIndex]) )
+ ++nNextIndex;
+ if ( nNextIndex >= nCount )
+ rAllowed = FALSE;
+ }
+
+ return TRUE; // found
+ }
+ return FALSE;
+}
+
+BOOL ScDPSource::SubTotalAllowed(long nColumn)
+{
+ //! cache this at ScDPResultData
+ BOOL bAllowed = TRUE;
+ if ( lcl_TestSubTotal( bAllowed, nColumn, nColDims, nColDimCount, this ) )
+ return bAllowed;
+ if ( lcl_TestSubTotal( bAllowed, nColumn, nRowDims, nRowDimCount, this ) )
+ return bAllowed;
+ return bAllowed;
+}
+
+void lcl_RemoveDim( long nRemove, long* pDims, long& rCount )
+{
+ for (long i=0; i<rCount; i++)
+ if ( pDims[i] == nRemove )
+ {
+ for (long j=i; j+1<rCount; j++)
+ pDims[j] = pDims[j+1];
+ --rCount;
+ return;
+ }
+}
+
+void ScDPSource::SetOrientation(long nColumn, USHORT nNew)
+{
+ //! change to no-op if new orientation is equal to old?
+
+ // remove from old list
+ lcl_RemoveDim( nColumn, nColDims, nColDimCount );
+ lcl_RemoveDim( nColumn, nRowDims, nRowDimCount );
+ lcl_RemoveDim( nColumn, nDataDims, nDataDimCount );
+ lcl_RemoveDim( nColumn, nPageDims, nPageDimCount );
+
+ // add to new list
+ switch (nNew)
+ {
+ case sheet::DataPilotFieldOrientation_COLUMN:
+ nColDims[nColDimCount++] = nColumn;
+ break;
+ case sheet::DataPilotFieldOrientation_ROW:
+ nRowDims[nRowDimCount++] = nColumn;
+ break;
+ case sheet::DataPilotFieldOrientation_DATA:
+ nDataDims[nDataDimCount++] = nColumn;
+ break;
+ case sheet::DataPilotFieldOrientation_PAGE:
+ nPageDims[nPageDimCount++] = nColumn;
+ break;
+ case sheet::DataPilotFieldOrientation_HIDDEN:
+ /* Do not assert HIDDEN as it occurs e.g. while using the
+ csss.XDataPilotTables.createDataPilotDescriptor() function. */
+ break;
+ default:
+ DBG_ERROR( "ScDPSource::SetOrientation: unexpected orientation" );
+ break;
+ }
+}
+
+BOOL ScDPSource::IsDataLayoutDimension(long nDim)
+{
+ return nDim == pData->GetColumnCount();
+}
+
+USHORT ScDPSource::GetDataLayoutOrientation()
+{
+ return GetOrientation(pData->GetColumnCount());
+}
+
+BOOL ScDPSource::IsDateDimension(long nDim)
+{
+ return pData->IsDateDimension(nDim);
+}
+
+ScDPDimensions* ScDPSource::GetDimensionsObject()
+{
+ if (!pDimensions)
+ {
+ pDimensions = new ScDPDimensions(this);
+ pDimensions->acquire(); // ref-counted
+ }
+ return pDimensions;
+}
+
+uno::Reference<container::XNameAccess> SAL_CALL ScDPSource::getDimensions() throw(uno::RuntimeException)
+{
+ return GetDimensionsObject();
+}
+
+void ScDPSource::SetDupCount( long nNew )
+{
+ nDupCount = nNew;
+}
+
+ScDPDimension* ScDPSource::AddDuplicated(long /* nSource */, const String& rNewName)
+{
+ DBG_ASSERT( pDimensions, "AddDuplicated without dimensions?" );
+
+ // re-use
+
+ long nOldDimCount = pDimensions->getCount();
+ for (long i=0; i<nOldDimCount; i++)
+ {
+ ScDPDimension* pDim = pDimensions->getByIndex(i);
+ if (pDim && String(pDim->getName()) == rNewName)
+ {
+ //! test if pDim is a duplicate of source
+ return pDim;
+ }
+ }
+
+ SetDupCount( nDupCount + 1 );
+ pDimensions->CountChanged(); // uses nDupCount
+
+ return pDimensions->getByIndex( pDimensions->getCount() - 1 );
+}
+
+long ScDPSource::GetSourceDim(long nDim)
+{
+ // original source dimension or data layout dimension?
+ if ( nDim <= pData->GetColumnCount() )
+ return nDim;
+
+ if ( nDim < pDimensions->getCount() )
+ {
+ ScDPDimension* pDimObj = pDimensions->getByIndex( nDim );
+ if ( pDimObj )
+ {
+ long nSource = pDimObj->GetSourceDim();
+ if ( nSource >= 0 )
+ return nSource;
+ }
+ }
+
+ DBG_ERROR("GetSourceDim: wrong dim");
+ return nDim;
+}
+
+uno::Sequence< uno::Sequence<sheet::DataResult> > SAL_CALL ScDPSource::getResults()
+ throw(uno::RuntimeException)
+{
+ CreateRes_Impl(); // create pColResRoot and pRowResRoot
+
+ if ( bResultOverflow ) // set in CreateRes_Impl
+ {
+ // no results available
+ throw uno::RuntimeException();
+ }
+
+ long nColCount = pColResRoot->GetSize(pResData->GetColStartMeasure());
+ long nRowCount = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
+
+ // allocate full sequence
+ //! leave out empty rows???
+
+ uno::Sequence< uno::Sequence<sheet::DataResult> > aSeq( nRowCount );
+ uno::Sequence<sheet::DataResult>* pRowAry = aSeq.getArray();
+ for (long nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<sheet::DataResult> aColSeq( nColCount );
+ // use default values of DataResult
+ pRowAry[nRow] = aColSeq;
+ }
+
+ long nSeqRow = 0;
+ pRowResRoot->FillDataResults( pColResRoot, aSeq, nSeqRow, pResData->GetRowStartMeasure() );
+
+ return aSeq;
+}
+
+void SAL_CALL ScDPSource::refresh() throw(uno::RuntimeException)
+{
+ disposeData();
+}
+
+void SAL_CALL ScDPSource::addRefreshListener( const uno::Reference<util::XRefreshListener >& )
+ throw(uno::RuntimeException)
+{
+ DBG_ERROR("not implemented"); //! exception?
+}
+
+void SAL_CALL ScDPSource::removeRefreshListener( const uno::Reference<util::XRefreshListener >& )
+ throw(uno::RuntimeException)
+{
+ DBG_ERROR("not implemented"); //! exception?
+}
+
+Sequence< Sequence<Any> > SAL_CALL ScDPSource::getDrillDownData(const Sequence<sheet::DataPilotFieldFilter>& aFilters)
+ throw (uno::RuntimeException)
+{
+ long nColumnCount = GetData()->GetColumnCount();
+ ScSimpleSharedString& rSharedString = GetData()->GetSharedString();
+
+ typedef hash_map<String, long, ScStringHashCode> FieldNameMapType;
+ FieldNameMapType aFieldNames;
+ for (long i = 0; i < nColumnCount; ++i)
+ {
+ aFieldNames.insert(
+ FieldNameMapType::value_type(GetData()->getDimensionName(i), i));
+ }
+
+ // collect ScDPItemData for each filtered column
+ vector<ScDPCacheTable::Criterion> aFilterCriteria;
+ sal_Int32 nFilterCount = aFilters.getLength();
+ for (sal_Int32 i = 0; i < nFilterCount; ++i)
+ {
+ const sheet::DataPilotFieldFilter& rFilter = aFilters[i];
+ String aFieldName( rFilter.FieldName );
+ for (long nCol = 0; nCol < nColumnCount; ++nCol)
+ {
+ if ( aFieldName == pData->getDimensionName(nCol) )
+ {
+ ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nCol );
+ ScDPMembers* pMembers = pDim->GetHierarchiesObject()->getByIndex(0)->
+ GetLevelsObject()->getByIndex(0)->GetMembersObject();
+ sal_Int32 nIndex = pMembers->GetIndexFromName( rFilter.MatchValue );
+ if ( nIndex >= 0 )
+ {
+ ScDPItemData aItem;
+ pMembers->getByIndex(nIndex)->FillItemData( aItem );
+ aFilterCriteria.push_back( ScDPCacheTable::Criterion() );
+ sal_Int32 nMatchStrId = rSharedString.getStringId(aItem.aString);
+ aFilterCriteria.back().mnFieldIndex = nCol;
+ aFilterCriteria.back().mpFilter.reset(
+ new ScDPCacheTable::SingleFilter(rSharedString, nMatchStrId, aItem.fValue, aItem.bHasValue) );
+ }
+ }
+ }
+ }
+
+ // Take into account the visibilities of field members.
+ ScDPResultVisibilityData aResVisData(rSharedString, this);
+ pRowResRoot->FillVisibilityData(aResVisData);
+ pColResRoot->FillVisibilityData(aResVisData);
+ aResVisData.fillFieldFilters(aFilterCriteria);
+
+ Sequence< Sequence<Any> > aTabData;
+ hash_set<sal_Int32> aCatDims;
+ GetCategoryDimensionIndices(aCatDims);
+ pData->GetDrillDownData(aFilterCriteria, aCatDims, aTabData);
+ return aTabData;
+}
+
+String ScDPSource::getDataDescription()
+{
+ CreateRes_Impl(); // create pResData
+
+ String aRet;
+ if ( pResData->GetMeasureCount() == 1 )
+ aRet = pResData->GetMeasureString( 0, TRUE, SUBTOTAL_FUNC_NONE );
+
+ // empty for more than one measure
+
+ return aRet;
+}
+
+BOOL ScDPSource::getColumnGrand() const
+{
+ return bColumnGrand;
+}
+
+void ScDPSource::setColumnGrand(BOOL bSet)
+{
+ bColumnGrand = bSet;
+}
+
+BOOL ScDPSource::getRowGrand() const
+{
+ return bRowGrand;
+}
+
+void ScDPSource::setRowGrand(BOOL bSet)
+{
+ bRowGrand = bSet;
+}
+
+BOOL ScDPSource::getIgnoreEmptyRows() const
+{
+ return bIgnoreEmptyRows;
+}
+
+void ScDPSource::setIgnoreEmptyRows(BOOL bSet)
+{
+ bIgnoreEmptyRows = bSet;
+ pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
+}
+
+BOOL ScDPSource::getRepeatIfEmpty() const
+{
+ return bRepeatIfEmpty;
+}
+
+void ScDPSource::setRepeatIfEmpty(BOOL bSet)
+{
+ bRepeatIfEmpty = bSet;
+ pData->SetEmptyFlags( bIgnoreEmptyRows, bRepeatIfEmpty );
+}
+
+void ScDPSource::validate() //! ???
+{
+ CreateRes_Impl();
+}
+
+void ScDPSource::disposeData()
+{
+ if ( pResData )
+ {
+ // reset all data...
+
+ DELETEZ(pColResRoot);
+ DELETEZ(pRowResRoot);
+ DELETEZ(pResData);
+ delete[] pColResults;
+ delete[] pRowResults;
+ pColResults = NULL;
+ pRowResults = NULL;
+ aColLevelList.Clear();
+ aRowLevelList.Clear();
+ }
+
+ if ( pDimensions )
+ {
+ pDimensions->release(); // ref-counted
+ pDimensions = NULL; // settings have to be applied (from SaveData) again!
+ }
+ SetDupCount( 0 );
+
+ //! Test ????
+ nColDimCount = nRowDimCount = nDataDimCount = nPageDimCount = 0;
+
+ pData->DisposeData(); // cached entries etc.
+ bResultOverflow = FALSE;
+}
+
+long lcl_CountMinMembers(const vector<ScDPDimension*>& ppDim, const vector<ScDPLevel*>& ppLevel, long nLevels )
+{
+ // Calculate the product of the member count for those consecutive levels that
+ // have the "show all" flag, one following level, and the data layout dimension.
+
+ long nTotal = 1;
+ long nDataCount = 1;
+ BOOL bWasShowAll = TRUE;
+ long nPos = nLevels;
+ while ( nPos > 0 )
+ {
+ --nPos;
+
+ if ( nPos+1 < nLevels && ppDim[nPos] == ppDim[nPos+1] )
+ {
+ DBG_ERROR("lcl_CountMinMembers: multiple levels from one dimension not implemented");
+ return 0;
+ }
+
+ BOOL bDo = FALSE;
+ if ( ppDim[nPos]->getIsDataLayoutDimension() )
+ {
+ // data layout dim doesn't interfere with "show all" flags
+ nDataCount = ppLevel[nPos]->GetMembersObject()->getCount();
+ if ( nDataCount == 0 )
+ nDataCount = 1;
+ }
+ else if ( bWasShowAll ) // "show all" set for all following levels?
+ {
+ bDo = TRUE;
+ if ( !ppLevel[nPos]->getShowEmpty() )
+ {
+ // this level is counted, following ones are not
+ bWasShowAll = FALSE;
+ }
+ }
+ if ( bDo )
+ {
+ long nThisCount = ppLevel[nPos]->GetMembersObject()->getMinMembers();
+ if ( nThisCount == 0 )
+ {
+ nTotal = 1; // empty level -> start counting from here
+ //! start with visible elements in this level?
+ }
+ else
+ {
+ if ( nTotal >= LONG_MAX / nThisCount )
+ return LONG_MAX; // overflow
+ nTotal *= nThisCount;
+ }
+ }
+ }
+
+ // always include data layout dim, even after restarting
+ if ( nTotal >= LONG_MAX / nDataCount )
+ return LONG_MAX; // overflow
+ nTotal *= nDataCount;
+
+ return nTotal;
+}
+
+long lcl_GetIndexFromName( const rtl::OUString rName, const uno::Sequence<rtl::OUString>& rElements )
+{
+ long nCount = rElements.getLength();
+ const rtl::OUString* pArray = rElements.getConstArray();
+ for (long nPos=0; nPos<nCount; nPos++)
+ if (pArray[nPos] == rName)
+ return nPos;
+
+ return -1; // not found
+}
+
+void ScDPSource::FillCalcInfo(bool bIsRow, ScDPTableData::CalcInfo& rInfo, bool &rHasAutoShow)
+{
+ long* nDims = bIsRow ? nRowDims : nColDims;
+ long nDimCount = bIsRow ? nRowDimCount : nColDimCount;
+
+ for (long i = 0; i < nDimCount; ++i)
+ {
+ ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nDims[i] );
+ long nHierarchy = pDim->getUsedHierarchy();
+ if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() )
+ nHierarchy = 0;
+ ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
+ long nCount = pLevels->getCount();
+
+ //! Test
+ if ( pDim->getIsDataLayoutDimension() && nDataDimCount < 2 )
+ nCount = 0;
+ //! Test
+
+ for (long j = 0; j < nCount; ++j)
+ {
+ ScDPLevel* pLevel = pLevels->getByIndex(j);
+ pLevel->EvaluateSortOrder();
+
+ // no layout flags for column fields, only for row fields
+ pLevel->SetEnableLayout( bIsRow );
+
+ if ( pLevel->GetAutoShow().IsEnabled )
+ rHasAutoShow = TRUE;
+
+ if (bIsRow)
+ {
+ rInfo.aRowLevelDims.push_back(nDims[i]);
+ rInfo.aRowDims.push_back(pDim);
+ rInfo.aRowLevels.push_back(pLevel);
+ }
+ else
+ {
+ rInfo.aColLevelDims.push_back(nDims[i]);
+ rInfo.aColDims.push_back(pDim);
+ rInfo.aColLevels.push_back(pLevel);
+ }
+
+ pLevel->GetMembersObject(); // initialize for groups
+ }
+ }
+}
+
+void ScDPSource::GetCategoryDimensionIndices(hash_set<sal_Int32>& rCatDims)
+{
+ hash_set<sal_Int32> aCatDims;
+ for (long i = 0; i < nColDimCount; ++i)
+ {
+ sal_Int32 nDim = static_cast<sal_Int32>(nColDims[i]);
+ if (!IsDataLayoutDimension(nDim))
+ aCatDims.insert(nDim);
+ }
+
+ for (long i = 0; i < nRowDimCount; ++i)
+ {
+ sal_Int32 nDim = static_cast<sal_Int32>(nRowDims[i]);
+ if (!IsDataLayoutDimension(nDim))
+ aCatDims.insert(nDim);
+ }
+
+ for (long i = 0; i < nPageDimCount; ++i)
+ {
+ sal_Int32 nDim = static_cast<sal_Int32>(nPageDims[i]);
+ if (!IsDataLayoutDimension(nDim))
+ aCatDims.insert(nDim);
+ }
+
+ rCatDims.swap(aCatDims);
+}
+
+void ScDPSource::FilterCacheTableByPageDimensions()
+{
+ ScSimpleSharedString& rSharedString = GetData()->GetSharedString();
+
+ // filter table by page dimensions.
+ vector<ScDPCacheTable::Criterion> aCriteria;
+ for (long i = 0; i < nPageDimCount; ++i)
+ {
+ ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nPageDims[i]);
+ long nField = pDim->GetDimension();
+
+ ScDPMembers* pMems = pDim->GetHierarchiesObject()->getByIndex(0)->
+ GetLevelsObject()->getByIndex(0)->GetMembersObject();
+
+ long nMemCount = pMems->getCount();
+ ScDPCacheTable::Criterion aFilter;
+ aFilter.mnFieldIndex = static_cast<sal_Int32>(nField);
+ aFilter.mpFilter.reset(new ScDPCacheTable::GroupFilter(rSharedString));
+ ScDPCacheTable::GroupFilter* pGrpFilter =
+ static_cast<ScDPCacheTable::GroupFilter*>(aFilter.mpFilter.get());
+ for (long j = 0; j < nMemCount; ++j)
+ {
+ ScDPMember* pMem = pMems->getByIndex(j);
+ if (pMem->getIsVisible())
+ {
+ ScDPItemData aData;
+ pMem->FillItemData(aData);
+ pGrpFilter->addMatchItem(aData.aString, aData.fValue, aData.bHasValue);
+ }
+ }
+ if (pGrpFilter->getMatchItemCount() < static_cast<size_t>(nMemCount))
+ // there is at least one invisible item. Add this filter criterion to the mix.
+ aCriteria.push_back(aFilter);
+
+ if (!pDim || !pDim->HasSelectedPage())
+ continue;
+
+ const ScDPItemData& rData = pDim->GetSelectedData();
+ aCriteria.push_back(ScDPCacheTable::Criterion());
+ ScDPCacheTable::Criterion& r = aCriteria.back();
+ r.mnFieldIndex = static_cast<sal_Int32>(nField);
+ sal_Int32 nStrId = rSharedString.getStringId(rData.aString);
+ r.mpFilter.reset(
+ new ScDPCacheTable::SingleFilter(rSharedString, nStrId, rData.fValue, rData.bHasValue));
+ }
+ if (!aCriteria.empty())
+ {
+ hash_set<sal_Int32> aCatDims;
+ GetCategoryDimensionIndices(aCatDims);
+ pData->FilterCacheTable(aCriteria, aCatDims);
+ }
+}
+
+void ScDPSource::CreateRes_Impl()
+{
+ if ( !pResData )
+ {
+ USHORT nDataOrient = GetDataLayoutOrientation();
+ if ( nDataDimCount > 1 && ( nDataOrient != sheet::DataPilotFieldOrientation_COLUMN &&
+ nDataOrient != sheet::DataPilotFieldOrientation_ROW ) )
+ {
+ // if more than one data dimension, data layout orientation must be set
+ SetOrientation( pData->GetColumnCount(), sheet::DataPilotFieldOrientation_ROW );
+ nDataOrient = sheet::DataPilotFieldOrientation_ROW;
+ }
+
+ // TODO: Aggreate pDataNames, pDataRefValues, nDataRefOrient, and
+ // eDataFunctions into a structure and use vector instead of static
+ // or pointer arrays.
+ String* pDataNames = NULL;
+ sheet::DataPilotFieldReference* pDataRefValues = NULL;
+ ScSubTotalFunc eDataFunctions[SC_DAPI_MAXFIELDS];
+ USHORT nDataRefOrient[SC_DAPI_MAXFIELDS];
+ if (nDataDimCount)
+ {
+ pDataNames = new String[nDataDimCount];
+ pDataRefValues = new sheet::DataPilotFieldReference[nDataDimCount];
+ }
+
+ ScDPTableData::CalcInfo aInfo;
+
+
+ // LateInit (initialize only those rows/children that are used) can be used unless
+ // any data dimension needs reference values from column/row dimensions
+ BOOL bLateInit = TRUE;
+
+ // Go through all data dimensions (i.e. fields) and build their meta data
+ // so that they can be passed on to ScDPResultData instance later.
+ // TODO: aggregate all of data dimension info into a structure.
+ long i;
+ for (i=0; i<nDataDimCount; i++)
+ {
+ // Get function for each data field.
+ long nDimIndex = nDataDims[i];
+ ScDPDimension* pDim = GetDimensionsObject()->getByIndex(nDimIndex);
+ sheet::GeneralFunction eUser = (sheet::GeneralFunction)pDim->getFunction();
+ if (eUser == sheet::GeneralFunction_AUTO)
+ {
+ //! test for numeric data
+ eUser = sheet::GeneralFunction_SUM;
+ }
+
+ // Map UNO's enum to internal enum ScSubTotalFunc.
+ eDataFunctions[i] = ScDataUnoConversion::GeneralToSubTotal( eUser );
+
+ // Get reference field/item information.
+ pDataRefValues[i] = pDim->GetReferenceValue();
+ nDataRefOrient[i] = sheet::DataPilotFieldOrientation_HIDDEN; // default if not used
+ sal_Int32 eRefType = pDataRefValues[i].ReferenceType;
+ if ( eRefType == sheet::DataPilotFieldReferenceType::ITEM_DIFFERENCE ||
+ eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE ||
+ eRefType == sheet::DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE ||
+ eRefType == sheet::DataPilotFieldReferenceType::RUNNING_TOTAL )
+ {
+ long nColumn = lcl_GetIndexFromName( pDataRefValues[i].ReferenceField,
+ GetDimensionsObject()->getElementNames() );
+ if ( nColumn >= 0 )
+ {
+ nDataRefOrient[i] = GetOrientation( nColumn );
+ // need fully initialized results to find reference values
+ // (both in column or row dimensions), so updated values or
+ // differences to 0 can be displayed even for empty results.
+ bLateInit = FALSE;
+ }
+ }
+
+ pDataNames[i] = String( pDim->getName() ); //! label?
+
+ // asterisk is added to duplicated dimension names by ScDPSaveData::WriteToSource
+ //! modify user visible strings as in ScDPResultData::GetMeasureString instead!
+
+ pDataNames[i].EraseTrailingChars('*');
+
+ //! if the name is overridden by user, a flag must be set
+ //! so the user defined name replaces the function string and field name.
+
+ //! the complete name (function and field) must be stored at the dimension
+
+ long nSource = ((ScDPDimension*)pDim)->GetSourceDim();
+ if (nSource >= 0)
+ aInfo.aDataSrcCols.push_back(nSource);
+ else
+ aInfo.aDataSrcCols.push_back(nDimIndex);
+ }
+
+ pResData = new ScDPResultData( this );
+ pResData->SetMeasureData( nDataDimCount, eDataFunctions, pDataRefValues, nDataRefOrient, pDataNames );
+ pResData->SetDataLayoutOrientation(nDataOrient);
+ pResData->SetLateInit( bLateInit );
+
+ delete[] pDataNames;
+ delete[] pDataRefValues;
+
+ bool bHasAutoShow = false;
+
+ ScDPInitState aInitState;
+
+ // Page field selections restrict the members shown in related fields
+ // (both in column and row fields). aInitState is filled with the page
+ // field selections, they are kept across the data iterator loop.
+
+ for (i=0; i<nPageDimCount; i++)
+ {
+ ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nPageDims[i] );
+ if ( pDim->HasSelectedPage() )
+ aInitState.AddMember( nPageDims[i], pDim->GetSelectedData() );
+ }
+
+ pColResRoot = new ScDPResultMember( pResData, NULL, NULL, NULL, bColumnGrand );
+ pRowResRoot = new ScDPResultMember( pResData, NULL, NULL, NULL, bRowGrand );
+
+ FillCalcInfo(false, aInfo, bHasAutoShow);
+ long nColLevelCount = aInfo.aColLevels.size();
+
+ pColResRoot->InitFrom( aInfo.aColDims, aInfo.aColLevels, 0, aInitState );
+ pColResRoot->SetHasElements();
+
+ FillCalcInfo(true, aInfo, bHasAutoShow);
+ long nRowLevelCount = aInfo.aRowLevels.size();
+
+ if ( nRowLevelCount > 0 )
+ {
+ // disable layout flags for the innermost row field (level)
+ aInfo.aRowLevels[nRowLevelCount-1]->SetEnableLayout( FALSE );
+ }
+
+ pRowResRoot->InitFrom( aInfo.aRowDims, aInfo.aRowLevels, 0, aInitState );
+ pRowResRoot->SetHasElements();
+
+ // initialize members object also for all page dimensions (needed for numeric groups)
+ for (i=0; i<nPageDimCount; i++)
+ {
+ ScDPDimension* pDim = GetDimensionsObject()->getByIndex( nPageDims[i] );
+ long nHierarchy = pDim->getUsedHierarchy();
+ if ( nHierarchy >= pDim->GetHierarchiesObject()->getCount() )
+ nHierarchy = 0;
+
+ ScDPLevels* pLevels = pDim->GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
+ long nCount = pLevels->getCount();
+ for (long j=0; j<nCount; j++)
+ pLevels->getByIndex(j)->GetMembersObject(); // initialize for groups
+ }
+
+ // pre-check: calculate minimum number of result columns / rows from
+ // levels that have the "show all" flag set
+
+ long nMinColMembers = lcl_CountMinMembers( aInfo.aColDims, aInfo.aColLevels, nColLevelCount );
+ long nMinRowMembers = lcl_CountMinMembers( aInfo.aRowDims, aInfo.aRowLevels, nRowLevelCount );
+
+ if ( nMinColMembers > SC_MINCOUNT_LIMIT || nMinRowMembers > SC_MINCOUNT_LIMIT )
+ {
+ // resulting table is too big -> abort before calculating
+ // (this relies on late init, so no members are allocated in InitFrom above)
+
+ bResultOverflow = TRUE;
+ }
+ else
+ {
+ FilterCacheTableByPageDimensions();
+
+ aInfo.aPageDims.reserve(nPageDimCount);
+ for (i = 0; i < nPageDimCount; ++i)
+ aInfo.aPageDims.push_back(nPageDims[i]);
+
+ aInfo.pInitState = &aInitState;
+ aInfo.pColRoot = pColResRoot;
+ aInfo.pRowRoot = pRowResRoot;
+ pData->CalcResults(aInfo, false);
+
+ // ----------------------------------------------------------------
+ // With all data processed, calculate the final results:
+
+ // UpdateDataResults calculates all original results from the collected values,
+ // and stores them as reference values if needed.
+ pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() );
+
+ if ( bHasAutoShow ) // do the double calculation only if AutoShow is used
+ {
+ // Find the desired members and set bAutoHidden flag for the others
+ pRowResRoot->DoAutoShow( pColResRoot );
+
+ // Reset all results to empty, so they can be built again with data for the
+ // desired members only.
+ pColResRoot->ResetResults( TRUE );
+ pRowResRoot->ResetResults( TRUE );
+ pData->CalcResults(aInfo, true);
+
+ // Call UpdateDataResults again, with the new (limited) values.
+ pRowResRoot->UpdateDataResults( pColResRoot, pResData->GetRowStartMeasure() );
+ }
+
+ // SortMembers does the sorting by a result dimension, using the orginal results,
+ // but not running totals etc.
+ pRowResRoot->SortMembers( pColResRoot );
+
+ // UpdateRunningTotals calculates running totals along column/row dimensions,
+ // differences from other members (named or relative), and column/row percentages
+ // or index values.
+ // Running totals and relative differences need to be done using the sorted values.
+ // Column/row percentages and index values must be done after sorting, because the
+ // results may no longer be in the right order (row total for percentage of row is
+ // always 1).
+ ScDPRunningTotalState aRunning( pColResRoot, pRowResRoot );
+ ScDPRowTotals aTotals;
+ pRowResRoot->UpdateRunningTotals( pColResRoot, pResData->GetRowStartMeasure(), aRunning, aTotals );
+
+ // ----------------------------------------------------------------
+ }
+ }
+}
+
+void ScDPSource::DumpState( ScDocument* pDoc, const ScAddress& rPos )
+{
+ CreateRes_Impl();
+
+ ScAddress aDocPos( rPos );
+
+ if (pColResRoot->GetChildDimension())
+ pColResRoot->GetChildDimension()->DumpState( NULL, pDoc, aDocPos );
+ pRowResRoot->DumpState( pColResRoot, pDoc, aDocPos );
+}
+
+void ScDPSource::FillLevelList( USHORT nOrientation, List& rList )
+{
+ rList.Clear();
+
+ long nDimCount = 0;
+ long* pDimIndex = NULL;
+ switch (nOrientation)
+ {
+ case sheet::DataPilotFieldOrientation_COLUMN:
+ pDimIndex = nColDims;
+ nDimCount = nColDimCount;
+ break;
+ case sheet::DataPilotFieldOrientation_ROW:
+ pDimIndex = nRowDims;
+ nDimCount = nRowDimCount;
+ break;
+ case sheet::DataPilotFieldOrientation_DATA:
+ pDimIndex = nDataDims;
+ nDimCount = nDataDimCount;
+ break;
+ case sheet::DataPilotFieldOrientation_PAGE:
+ pDimIndex = nPageDims;
+ nDimCount = nPageDimCount;
+ break;
+ default:
+ DBG_ERROR( "ScDPSource::FillLevelList: unexpected orientation" );
+ break;
+ }
+ if (!pDimIndex)
+ {
+ DBG_ERROR("invalid orientation");
+ return;
+ }
+
+ ScDPDimensions* pDims = GetDimensionsObject();
+ for (long nDim=0; nDim<nDimCount; nDim++)
+ {
+ ScDPDimension* pDim = pDims->getByIndex(pDimIndex[nDim]);
+ DBG_ASSERT( pDim->getOrientation() == nOrientation, "orientations are wrong" );
+
+ ScDPHierarchies* pHiers = pDim->GetHierarchiesObject();
+ long nHierarchy = pDim->getUsedHierarchy();
+ if ( nHierarchy >= pHiers->getCount() )
+ nHierarchy = 0;
+ ScDPHierarchy* pHier = pHiers->getByIndex(nHierarchy);
+ ScDPLevels* pLevels = pHier->GetLevelsObject();
+ long nLevCount = pLevels->getCount();
+ for (long nLev=0; nLev<nLevCount; nLev++)
+ {
+ ScDPLevel* pLevel = pLevels->getByIndex(nLev);
+ rList.Insert( pLevel, LIST_APPEND );
+ }
+ }
+}
+
+void ScDPSource::FillMemberResults()
+{
+ if ( !pColResults && !pRowResults )
+ {
+ CreateRes_Impl();
+
+ if ( bResultOverflow ) // set in CreateRes_Impl
+ {
+ // no results available -> abort (leave empty)
+ // exception is thrown in ScDPSource::getResults
+ return;
+ }
+
+ FillLevelList( sheet::DataPilotFieldOrientation_COLUMN, aColLevelList );
+ long nColLevelCount = aColLevelList.Count();
+ if (nColLevelCount)
+ {
+ long nColDimSize = pColResRoot->GetSize(pResData->GetColStartMeasure());
+ pColResults = new uno::Sequence<sheet::MemberResult>[nColLevelCount];
+ for (long i=0; i<nColLevelCount; i++)
+ pColResults[i].realloc(nColDimSize);
+
+ // ScDPResultDimension* pColResDim = pColResRoot->GetChildDimension();
+ // pColResDim->FillMemberResults( pColResults, 0, pResData->GetColStartMeasure() );
+ long nPos = 0;
+ pColResRoot->FillMemberResults( pColResults, nPos, pResData->GetColStartMeasure(),
+ TRUE, NULL, NULL );
+ }
+
+ FillLevelList( sheet::DataPilotFieldOrientation_ROW, aRowLevelList );
+ long nRowLevelCount = aRowLevelList.Count();
+ if (nRowLevelCount)
+ {
+ long nRowDimSize = pRowResRoot->GetSize(pResData->GetRowStartMeasure());
+ pRowResults = new uno::Sequence<sheet::MemberResult>[nRowLevelCount];
+ for (long i=0; i<nRowLevelCount; i++)
+ pRowResults[i].realloc(nRowDimSize);
+
+ // ScDPResultDimension* pRowResDim = pRowResRoot->GetChildDimension();
+ // pRowResDim->FillMemberResults( pRowResults, 0, pResData->GetRowStartMeasure() );
+ long nPos = 0;
+ pRowResRoot->FillMemberResults( pRowResults, nPos, pResData->GetRowStartMeasure(),
+ TRUE, NULL, NULL );
+ }
+ }
+}
+
+const uno::Sequence<sheet::MemberResult>* ScDPSource::GetMemberResults( ScDPLevel* pLevel )
+{
+ FillMemberResults();
+
+ long i;
+ long nColCount = aColLevelList.Count();
+ for (i=0; i<nColCount; i++)
+ {
+ ScDPLevel* pColLevel = (ScDPLevel*)aColLevelList.GetObject(i);
+ if ( pColLevel == pLevel )
+ return pColResults+i;
+ }
+ long nRowCount = aRowLevelList.Count();
+ for (i=0; i<nRowCount; i++)
+ {
+ ScDPLevel* pRowLevel = (ScDPLevel*)aRowLevelList.GetObject(i);
+ if ( pRowLevel == pLevel )
+ return pRowResults+i;
+ }
+ return NULL;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPSource::getPropertySetInfo()
+ throw(uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+
+ static SfxItemPropertyMap aDPSourceMap_Impl[] =
+ {
+ {MAP_CHAR_LEN(SC_UNO_COLGRAND), 0, &getBooleanCppuType(), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_DATADESC), 0, &getCppuType((rtl::OUString*)0), beans::PropertyAttribute::READONLY, 0 },
+ {MAP_CHAR_LEN(SC_UNO_IGNOREEM), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only
+ {MAP_CHAR_LEN(SC_UNO_REPEATIF), 0, &getBooleanCppuType(), 0, 0 }, // for sheet data only
+ {MAP_CHAR_LEN(SC_UNO_ROWGRAND), 0, &getBooleanCppuType(), 0, 0 },
+ {0,0,0,0,0,0}
+ };
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( aDPSourceMap_Impl );
+ return aRef;
+}
+
+void SAL_CALL ScDPSource::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
+ throw(beans::UnknownPropertyException, beans::PropertyVetoException,
+ lang::IllegalArgumentException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ String aNameStr = aPropertyName;
+ if ( aNameStr.EqualsAscii( SC_UNO_COLGRAND ) )
+ setColumnGrand( lcl_GetBoolFromAny( aValue ) );
+ else if ( aNameStr.EqualsAscii( SC_UNO_ROWGRAND ) )
+ setRowGrand( lcl_GetBoolFromAny( aValue ) );
+ else if ( aNameStr.EqualsAscii( SC_UNO_IGNOREEM ) )
+ setIgnoreEmptyRows( lcl_GetBoolFromAny( aValue ) );
+ else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) )
+ setRepeatIfEmpty( lcl_GetBoolFromAny( aValue ) );
+ else
+ {
+ DBG_ERROR("unknown property");
+ //! THROW( UnknownPropertyException() );
+ }
+}
+
+uno::Any SAL_CALL ScDPSource::getPropertyValue( const rtl::OUString& aPropertyName )
+ throw(beans::UnknownPropertyException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ uno::Any aRet;
+ String aNameStr = aPropertyName;
+ if ( aNameStr.EqualsAscii( SC_UNO_COLGRAND ) )
+ lcl_SetBoolInAny( aRet, getColumnGrand() );
+ else if ( aNameStr.EqualsAscii( SC_UNO_ROWGRAND ) )
+ lcl_SetBoolInAny( aRet, getRowGrand() );
+ else if ( aNameStr.EqualsAscii( SC_UNO_IGNOREEM ) )
+ lcl_SetBoolInAny( aRet, getIgnoreEmptyRows() );
+ else if ( aNameStr.EqualsAscii( SC_UNO_REPEATIF ) )
+ lcl_SetBoolInAny( aRet, getRepeatIfEmpty() );
+ else if ( aNameStr.EqualsAscii( SC_UNO_DATADESC ) ) // read-only
+ aRet <<= rtl::OUString( getDataDescription() );
+ else if ( aNameStr.EqualsAscii( SC_UNO_ROWFIELDCOUNT ) ) // read-only
+ aRet <<= static_cast<sal_Int32>(nRowDimCount);
+ else if ( aNameStr.EqualsAscii( SC_UNO_COLUMNFIELDCOUNT ) ) // read-only
+ aRet <<= static_cast<sal_Int32>(nColDimCount);
+ else if ( aNameStr.EqualsAscii( SC_UNO_DATAFIELDCOUNT ) ) // read-only
+ aRet <<= static_cast<sal_Int32>(nDataDimCount);
+ else
+ {
+ DBG_ERROR("unknown property");
+ //! THROW( UnknownPropertyException() );
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPSource )
+
+// -----------------------------------------------------------------------
+
+ScDPDimensions::ScDPDimensions( ScDPSource* pSrc ) :
+ pSource( pSrc ),
+ ppDims( NULL )
+{
+ //! hold pSource
+
+ // include data layout dimension and duplicated dimensions
+ nDimCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount();
+}
+
+ScDPDimensions::~ScDPDimensions()
+{
+ //! release pSource
+
+ if (ppDims)
+ {
+ for (long i=0; i<nDimCount; i++)
+ if ( ppDims[i] )
+ ppDims[i]->release(); // ref-counted
+ delete[] ppDims;
+ }
+}
+
+void ScDPDimensions::CountChanged()
+{
+ // include data layout dimension and duplicated dimensions
+ long nNewCount = pSource->GetData()->GetColumnCount() + 1 + pSource->GetDupCount();
+ if ( ppDims )
+ {
+ long i;
+ long nCopy = Min( nNewCount, nDimCount );
+ ScDPDimension** ppNew = new ScDPDimension*[nNewCount];
+
+ for (i=0; i<nCopy; i++) // copy existing dims
+ ppNew[i] = ppDims[i];
+ for (i=nCopy; i<nNewCount; i++) // clear additional pointers
+ ppNew[i] = NULL;
+ for (i=nCopy; i<nDimCount; i++) // delete old dims if count is decreased
+ if ( ppDims[i] )
+ ppDims[i]->release(); // ref-counted
+
+ delete[] ppDims;
+ ppDims = ppNew;
+ }
+ nDimCount = nNewCount;
+}
+
+// very simple XNameAccess implementation using getCount/getByIndex
+
+uno::Any SAL_CALL ScDPDimensions::getByName( const rtl::OUString& aName )
+ throw(container::NoSuchElementException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ long nCount = getCount();
+ for (long i=0; i<nCount; i++)
+ if ( getByIndex(i)->getName() == aName )
+ {
+ uno::Reference<container::XNamed> xNamed = getByIndex(i);
+ uno::Any aRet;
+ aRet <<= xNamed;
+ return aRet;
+ }
+
+ throw container::NoSuchElementException();
+// return uno::Any();
+}
+
+uno::Sequence<rtl::OUString> SAL_CALL ScDPDimensions::getElementNames() throw(uno::RuntimeException)
+{
+ long nCount = getCount();
+ uno::Sequence<rtl::OUString> aSeq(nCount);
+ rtl::OUString* pArr = aSeq.getArray();
+ for (long i=0; i<nCount; i++)
+ pArr[i] = getByIndex(i)->getName();
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScDPDimensions::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
+{
+ long nCount = getCount();
+ for (long i=0; i<nCount; i++)
+ if ( getByIndex(i)->getName() == aName )
+ return TRUE;
+ return FALSE;
+}
+
+uno::Type SAL_CALL ScDPDimensions::getElementType() throw(uno::RuntimeException)
+{
+ return getCppuType((uno::Reference<container::XNamed>*)0);
+}
+
+sal_Bool SAL_CALL ScDPDimensions::hasElements() throw(uno::RuntimeException)
+{
+ return ( getCount() > 0 );
+}
+
+// end of XNameAccess implementation
+
+long ScDPDimensions::getCount() const
+{
+ // in tabular data, every column of source data is a dimension
+
+ return nDimCount;
+}
+
+ScDPDimension* ScDPDimensions::getByIndex(long nIndex) const
+{
+ if ( nIndex >= 0 && nIndex < nDimCount )
+ {
+ if ( !ppDims )
+ {
+ ((ScDPDimensions*)this)->ppDims = new ScDPDimension*[nDimCount];
+ for (long i=0; i<nDimCount; i++)
+ ppDims[i] = NULL;
+ }
+ if ( !ppDims[nIndex] )
+ {
+ ppDims[nIndex] = new ScDPDimension( pSource, nIndex );
+ ppDims[nIndex]->acquire(); // ref-counted
+ }
+
+ return ppDims[nIndex];
+ }
+
+ return NULL; //! exception?
+}
+
+// -----------------------------------------------------------------------
+
+ScDPDimension::ScDPDimension( ScDPSource* pSrc, long nD ) :
+ pSource( pSrc ),
+ nDim( nD ),
+ pHierarchies( NULL ),
+ nUsedHier( 0 ),
+ nFunction( SUBTOTAL_FUNC_SUM ), // sum is default
+ nSourceDim( -1 ),
+ bHasSelectedPage( FALSE ),
+ pSelectedData( NULL )
+{
+ //! hold pSource
+}
+
+ScDPDimension::~ScDPDimension()
+{
+ //! release pSource
+
+ if ( pHierarchies )
+ pHierarchies->release(); // ref-counted
+
+ delete pSelectedData;
+}
+
+ScDPHierarchies* ScDPDimension::GetHierarchiesObject()
+{
+ if (!pHierarchies)
+ {
+ pHierarchies = new ScDPHierarchies( pSource, nDim );
+ pHierarchies->acquire(); // ref-counted
+ }
+ return pHierarchies;
+}
+
+uno::Reference<container::XNameAccess> SAL_CALL ScDPDimension::getHierarchies()
+ throw(uno::RuntimeException)
+{
+ return GetHierarchiesObject();
+}
+
+::rtl::OUString SAL_CALL ScDPDimension::getName() throw(uno::RuntimeException)
+{
+ if (aName.Len())
+ return aName;
+ else
+ return pSource->GetData()->getDimensionName( nDim );
+}
+
+void SAL_CALL ScDPDimension::setName( const ::rtl::OUString& rNewName ) throw(uno::RuntimeException)
+{
+ // used after cloning
+ aName = String( rNewName );
+}
+
+USHORT ScDPDimension::getOrientation() const
+{
+ return pSource->GetOrientation( nDim );
+}
+
+void ScDPDimension::setOrientation(USHORT nNew)
+{
+ pSource->SetOrientation( nDim, nNew );
+}
+
+long ScDPDimension::getPosition() const
+{
+ return pSource->GetPosition( nDim );
+}
+
+void ScDPDimension::setPosition(long /* nNew */)
+{
+ //! ...
+}
+
+BOOL ScDPDimension::getIsDataLayoutDimension() const
+{
+ return pSource->GetData()->getIsDataLayoutDimension( nDim );
+}
+
+USHORT ScDPDimension::getFunction() const
+{
+ return nFunction;
+}
+
+void ScDPDimension::setFunction(USHORT nNew)
+{
+ nFunction = nNew;
+}
+
+long ScDPDimension::getUsedHierarchy() const
+{
+ return nUsedHier;
+}
+
+void ScDPDimension::setUsedHierarchy(long /* nNew */)
+{
+ // #i52547# don't use the incomplete date hierarchy implementation - ignore the call
+ // nUsedHier = nNew;
+}
+
+ScDPDimension* ScDPDimension::CreateCloneObject()
+{
+ DBG_ASSERT( nSourceDim < 0, "recursive duplicate - not implemented" );
+
+ //! set new name here, or temporary name ???
+ String aNewName = aName;
+
+ ScDPDimension* pNew = pSource->AddDuplicated( nDim, aNewName );
+
+ pNew->aName = aNewName; //! here or in source?
+ pNew->nSourceDim = nDim; //! recursive?
+
+ return pNew;
+}
+
+uno::Reference<util::XCloneable> SAL_CALL ScDPDimension::createClone() throw(uno::RuntimeException)
+{
+ return CreateCloneObject();
+}
+
+BOOL ScDPDimension::isDuplicated() const
+{
+ return (nSourceDim >= 0);
+}
+
+const sheet::DataPilotFieldReference& ScDPDimension::GetReferenceValue() const
+{
+ return aReferenceValue;
+}
+
+const ScDPItemData& ScDPDimension::GetSelectedData()
+{
+ if ( !pSelectedData )
+ {
+ // find the named member to initialize pSelectedData from it, with name and value
+
+ long nLevel = 0; // same as in ScDPObject::FillPageList
+
+ long nHierarchy = getUsedHierarchy();
+ if ( nHierarchy >= GetHierarchiesObject()->getCount() )
+ nHierarchy = 0;
+ ScDPLevels* pLevels = GetHierarchiesObject()->getByIndex(nHierarchy)->GetLevelsObject();
+ long nLevCount = pLevels->getCount();
+ if ( nLevel < nLevCount )
+ {
+ ScDPMembers* pMembers = pLevels->getByIndex(nLevel)->GetMembersObject();
+
+ //! merge with ScDPMembers::getByName
+ long nCount = pMembers->getCount();
+ for (long i=0; i<nCount && !pSelectedData; i++)
+ {
+ ScDPMember* pMember = pMembers->getByIndex(i);
+ if ( pMember->GetNameStr() == aSelectedPage )
+ {
+ pSelectedData = new ScDPItemData();
+ pMember->FillItemData( *pSelectedData );
+ }
+ }
+ }
+
+ if ( !pSelectedData )
+ pSelectedData = new ScDPItemData( aSelectedPage, 0.0, FALSE ); // default - name only
+ }
+
+ return *pSelectedData;
+}
+
+BOOL ScDPDimension::IsValidPage( const ScDPItemData& rData )
+{
+ if ( bHasSelectedPage )
+ return rData.IsCaseInsEqual( GetSelectedData() );
+
+ return TRUE; // no selection -> all data
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPDimension::getPropertySetInfo()
+ throw(uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+
+ static SfxItemPropertyMap aDPDimensionMap_Impl[] =
+ {
+ {MAP_CHAR_LEN(SC_UNO_FILTER), 0, &getCppuType((uno::Sequence<sheet::TableFilterField>*)0), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_FUNCTION), 0, &getCppuType((sheet::GeneralFunction*)0), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_ISDATALA), 0, &getBooleanCppuType(), beans::PropertyAttribute::READONLY, 0 },
+ {MAP_CHAR_LEN(SC_UNO_NUMBERFO), 0, &getCppuType((sal_Int32*)0), beans::PropertyAttribute::READONLY, 0 },
+ {MAP_CHAR_LEN(SC_UNO_ORIENTAT), 0, &getCppuType((sheet::DataPilotFieldOrientation*)0), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_ORIGINAL), 0, &getCppuType((uno::Reference<container::XNamed>*)0), beans::PropertyAttribute::READONLY, 0 },
+ {MAP_CHAR_LEN(SC_UNO_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_REFVALUE), 0, &getCppuType((sheet::DataPilotFieldReference*)0), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_USEDHIER), 0, &getCppuType((sal_Int32*)0), 0, 0 },
+ {0,0,0,0,0,0}
+ };
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( aDPDimensionMap_Impl );
+ return aRef;
+}
+
+void SAL_CALL ScDPDimension::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
+ throw(beans::UnknownPropertyException, beans::PropertyVetoException,
+ lang::IllegalArgumentException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ String aNameStr = aPropertyName;
+ if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
+ {
+ INT32 nInt = 0;
+ if (aValue >>= nInt)
+ setPosition( nInt );
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) )
+ {
+ INT32 nInt = 0;
+ if (aValue >>= nInt)
+ setUsedHierarchy( nInt );
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_ORIENTAT ) )
+ {
+ sheet::DataPilotFieldOrientation eEnum;
+ if (aValue >>= eEnum)
+ setOrientation( sal::static_int_cast<USHORT>(eEnum) );
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) )
+ {
+ sheet::GeneralFunction eEnum;
+ if (aValue >>= eEnum)
+ setFunction( sal::static_int_cast<USHORT>(eEnum) );
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) )
+ aValue >>= aReferenceValue;
+ else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) )
+ {
+ BOOL bDone = FALSE;
+ uno::Sequence<sheet::TableFilterField> aSeq;
+ if (aValue >>= aSeq)
+ {
+ sal_Int32 nLength = aSeq.getLength();
+ if ( nLength == 0 )
+ {
+ aSelectedPage.Erase();
+ bHasSelectedPage = FALSE;
+ bDone = TRUE;
+ }
+ else if ( nLength == 1 )
+ {
+ const sheet::TableFilterField& rField = aSeq[0];
+ if ( rField.Field == 0 && rField.Operator == sheet::FilterOperator_EQUAL && !rField.IsNumeric )
+ {
+ aSelectedPage = rField.StringValue;
+ bHasSelectedPage = TRUE;
+ bDone = TRUE;
+ }
+ }
+ }
+ if ( !bDone )
+ {
+ DBG_ERROR("Filter property is not a single string");
+ throw lang::IllegalArgumentException();
+ }
+ DELETEZ( pSelectedData ); // invalid after changing aSelectedPage
+ }
+ else
+ {
+ DBG_ERROR("unknown property");
+ //! THROW( UnknownPropertyException() );
+ }
+}
+
+uno::Any SAL_CALL ScDPDimension::getPropertyValue( const rtl::OUString& aPropertyName )
+ throw(beans::UnknownPropertyException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ uno::Any aRet;
+ String aNameStr = aPropertyName;
+ if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
+ aRet <<= (sal_Int32) getPosition();
+ else if ( aNameStr.EqualsAscii( SC_UNO_USEDHIER ) )
+ aRet <<= (sal_Int32) getUsedHierarchy();
+ else if ( aNameStr.EqualsAscii( SC_UNO_ORIENTAT ) )
+ {
+ sheet::DataPilotFieldOrientation eVal = (sheet::DataPilotFieldOrientation)getOrientation();
+ aRet <<= eVal;
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_FUNCTION ) )
+ {
+ sheet::GeneralFunction eVal = (sheet::GeneralFunction)getFunction();
+ aRet <<= eVal;
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_REFVALUE ) )
+ aRet <<= aReferenceValue;
+ else if ( aNameStr.EqualsAscii( SC_UNO_ISDATALA ) ) // read-only properties
+ lcl_SetBoolInAny( aRet, getIsDataLayoutDimension() );
+ else if ( aNameStr.EqualsAscii( SC_UNO_NUMBERFO ) )
+ {
+ sal_Int32 nFormat = 0;
+ sheet::GeneralFunction eFunc = (sheet::GeneralFunction)getFunction();
+ // #i63745# don't use source format for "count"
+ if ( eFunc != sheet::GeneralFunction_COUNT && eFunc != sheet::GeneralFunction_COUNTNUMS )
+ nFormat = pSource->GetData()->GetNumberFormat( ( nSourceDim >= 0 ) ? nSourceDim : nDim );
+ aRet <<= nFormat;
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_ORIGINAL ) )
+ {
+ uno::Reference<container::XNamed> xOriginal;
+ if (nSourceDim >= 0)
+ xOriginal = pSource->GetDimensionsObject()->getByIndex(nSourceDim);
+ aRet <<= xOriginal;
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_FILTER ) )
+ {
+ if ( bHasSelectedPage )
+ {
+ // single filter field: first field equal to selected string
+ sheet::TableFilterField aField( sheet::FilterConnection_AND, 0,
+ sheet::FilterOperator_EQUAL, sal_False, 0.0, aSelectedPage );
+ aRet <<= uno::Sequence<sheet::TableFilterField>( &aField, 1 );
+ }
+ else
+ aRet <<= uno::Sequence<sheet::TableFilterField>(0);
+ }
+ else
+ {
+ DBG_ERROR("unknown property");
+ //! THROW( UnknownPropertyException() );
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPDimension )
+
+// -----------------------------------------------------------------------
+
+ScDPHierarchies::ScDPHierarchies( ScDPSource* pSrc, long nD ) :
+ pSource( pSrc ),
+ nDim( nD ),
+ ppHiers( NULL )
+{
+ //! hold pSource
+
+#if 0
+ // date columns have 3 hierarchies (flat/quarter/week), other columns only one
+ long nSrcDim = pSource->GetSourceDim( nDim );
+ if ( pSource->IsDateDimension( nSrcDim ) )
+ nHierCount = SC_DAPI_DATE_HIERARCHIES;
+ else
+ nHierCount = 1;
+#endif
+
+ // #i52547# don't offer the incomplete date hierarchy implementation
+ nHierCount = 1;
+}
+
+ScDPHierarchies::~ScDPHierarchies()
+{
+ //! release pSource
+
+ if (ppHiers)
+ {
+ for (long i=0; i<nHierCount; i++)
+ if ( ppHiers[i] )
+ ppHiers[i]->release(); // ref-counted
+ delete[] ppHiers;
+ }
+}
+
+// very simple XNameAccess implementation using getCount/getByIndex
+
+uno::Any SAL_CALL ScDPHierarchies::getByName( const rtl::OUString& aName )
+ throw(container::NoSuchElementException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ long nCount = getCount();
+ for (long i=0; i<nCount; i++)
+ if ( getByIndex(i)->getName() == aName )
+ {
+ uno::Reference<container::XNamed> xNamed = getByIndex(i);
+ uno::Any aRet;
+ aRet <<= xNamed;
+ return aRet;
+ }
+
+ throw container::NoSuchElementException();
+// return uno::Any();
+}
+
+uno::Sequence<rtl::OUString> SAL_CALL ScDPHierarchies::getElementNames() throw(uno::RuntimeException)
+{
+ long nCount = getCount();
+ uno::Sequence<rtl::OUString> aSeq(nCount);
+ rtl::OUString* pArr = aSeq.getArray();
+ for (long i=0; i<nCount; i++)
+ pArr[i] = getByIndex(i)->getName();
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScDPHierarchies::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
+{
+ long nCount = getCount();
+ for (long i=0; i<nCount; i++)
+ if ( getByIndex(i)->getName() == aName )
+ return TRUE;
+ return FALSE;
+}
+
+uno::Type SAL_CALL ScDPHierarchies::getElementType() throw(uno::RuntimeException)
+{
+ return getCppuType((uno::Reference<container::XNamed>*)0);
+}
+
+sal_Bool SAL_CALL ScDPHierarchies::hasElements() throw(uno::RuntimeException)
+{
+ return ( getCount() > 0 );
+}
+
+// end of XNameAccess implementation
+
+long ScDPHierarchies::getCount() const
+{
+ return nHierCount;
+}
+
+ScDPHierarchy* ScDPHierarchies::getByIndex(long nIndex) const
+{
+ // pass hierarchy index to new object in case the implementation
+ // will be extended to more than one hierarchy
+
+ if ( nIndex >= 0 && nIndex < nHierCount )
+ {
+ if ( !ppHiers )
+ {
+ ((ScDPHierarchies*)this)->ppHiers = new ScDPHierarchy*[nHierCount];
+ for (long i=0; i<nHierCount; i++)
+ ppHiers[i] = NULL;
+ }
+ if ( !ppHiers[nIndex] )
+ {
+ ppHiers[nIndex] = new ScDPHierarchy( pSource, nDim, nIndex );
+ ppHiers[nIndex]->acquire(); // ref-counted
+ }
+
+ return ppHiers[nIndex];
+ }
+
+ return NULL; //! exception?
+}
+
+// -----------------------------------------------------------------------
+
+ScDPHierarchy::ScDPHierarchy( ScDPSource* pSrc, long nD, long nH ) :
+ pSource( pSrc ),
+ nDim( nD ),
+ nHier( nH ),
+ pLevels( NULL )
+{
+ //! hold pSource
+}
+
+ScDPHierarchy::~ScDPHierarchy()
+{
+ //! release pSource
+
+ if (pLevels)
+ pLevels->release(); // ref-counted
+}
+
+ScDPLevels* ScDPHierarchy::GetLevelsObject()
+{
+ if (!pLevels)
+ {
+ pLevels = new ScDPLevels( pSource, nDim, nHier );
+ pLevels->acquire(); // ref-counted
+ }
+ return pLevels;
+}
+
+uno::Reference<container::XNameAccess> SAL_CALL ScDPHierarchy::getLevels()
+ throw(uno::RuntimeException)
+{
+ return GetLevelsObject();
+}
+
+::rtl::OUString SAL_CALL ScDPHierarchy::getName() throw(uno::RuntimeException)
+{
+ String aRet; //! globstr-ID !!!!
+ switch (nHier)
+ {
+ case SC_DAPI_HIERARCHY_FLAT:
+ aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("flat"));
+ break; //! name ???????
+ case SC_DAPI_HIERARCHY_QUARTER:
+ aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Quarter"));
+ break; //! name ???????
+ case SC_DAPI_HIERARCHY_WEEK:
+ aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Week"));
+ break; //! name ???????
+ default:
+ DBG_ERROR( "ScDPHierarchy::getName: unexpected hierarchy" );
+ break;
+ }
+ return aRet;
+}
+
+void SAL_CALL ScDPHierarchy::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException)
+{
+ DBG_ERROR("not implemented"); //! exception?
+}
+
+// -----------------------------------------------------------------------
+
+ScDPLevels::ScDPLevels( ScDPSource* pSrc, long nD, long nH ) :
+ pSource( pSrc ),
+ nDim( nD ),
+ nHier( nH ),
+ ppLevs( NULL )
+{
+ //! hold pSource
+
+ // text columns have only one level
+
+ long nSrcDim = pSource->GetSourceDim( nDim );
+ if ( pSource->IsDateDimension( nSrcDim ) )
+ {
+ switch ( nHier )
+ {
+ case SC_DAPI_HIERARCHY_FLAT: nLevCount = SC_DAPI_FLAT_LEVELS; break;
+ case SC_DAPI_HIERARCHY_QUARTER: nLevCount = SC_DAPI_QUARTER_LEVELS; break;
+ case SC_DAPI_HIERARCHY_WEEK: nLevCount = SC_DAPI_WEEK_LEVELS; break;
+ default:
+ DBG_ERROR("wrong hierarchy");
+ nLevCount = 0;
+ }
+ }
+ else
+ nLevCount = 1;
+}
+
+ScDPLevels::~ScDPLevels()
+{
+ //! release pSource
+
+ if (ppLevs)
+ {
+ for (long i=0; i<nLevCount; i++)
+ if ( ppLevs[i] )
+ ppLevs[i]->release(); // ref-counted
+ delete[] ppLevs;
+ }
+}
+
+// very simple XNameAccess implementation using getCount/getByIndex
+
+uno::Any SAL_CALL ScDPLevels::getByName( const rtl::OUString& aName )
+ throw(container::NoSuchElementException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ long nCount = getCount();
+ for (long i=0; i<nCount; i++)
+ if ( getByIndex(i)->getName() == aName )
+ {
+ uno::Reference<container::XNamed> xNamed = getByIndex(i);
+ uno::Any aRet;
+ aRet <<= xNamed;
+ return aRet;
+ }
+
+ throw container::NoSuchElementException();
+// return uno::Any();
+}
+
+uno::Sequence<rtl::OUString> SAL_CALL ScDPLevels::getElementNames() throw(uno::RuntimeException)
+{
+ long nCount = getCount();
+ uno::Sequence<rtl::OUString> aSeq(nCount);
+ rtl::OUString* pArr = aSeq.getArray();
+ for (long i=0; i<nCount; i++)
+ pArr[i] = getByIndex(i)->getName();
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScDPLevels::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
+{
+ long nCount = getCount();
+ for (long i=0; i<nCount; i++)
+ if ( getByIndex(i)->getName() == aName )
+ return TRUE;
+ return FALSE;
+}
+
+uno::Type SAL_CALL ScDPLevels::getElementType() throw(uno::RuntimeException)
+{
+ return getCppuType((uno::Reference<container::XNamed>*)0);
+}
+
+sal_Bool SAL_CALL ScDPLevels::hasElements() throw(uno::RuntimeException)
+{
+ return ( getCount() > 0 );
+}
+
+// end of XNameAccess implementation
+
+long ScDPLevels::getCount() const
+{
+ return nLevCount;
+}
+
+ScDPLevel* ScDPLevels::getByIndex(long nIndex) const
+{
+ if ( nIndex >= 0 && nIndex < nLevCount )
+ {
+ if ( !ppLevs )
+ {
+ ((ScDPLevels*)this)->ppLevs = new ScDPLevel*[nLevCount];
+ for (long i=0; i<nLevCount; i++)
+ ppLevs[i] = NULL;
+ }
+ if ( !ppLevs[nIndex] )
+ {
+ ppLevs[nIndex] = new ScDPLevel( pSource, nDim, nHier, nIndex );
+ ppLevs[nIndex]->acquire(); // ref-counted
+ }
+
+ return ppLevs[nIndex];
+ }
+
+ return NULL; //! exception?
+}
+
+// -----------------------------------------------------------------------
+
+class ScDPGlobalMembersOrder
+{
+ ScDPLevel& rLevel;
+ BOOL bAscending;
+
+public:
+ ScDPGlobalMembersOrder( ScDPLevel& rLev, BOOL bAsc ) :
+ rLevel(rLev),
+ bAscending(bAsc)
+ {}
+ ~ScDPGlobalMembersOrder() {}
+
+ BOOL operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const;
+};
+
+BOOL ScDPGlobalMembersOrder::operator()( sal_Int32 nIndex1, sal_Int32 nIndex2 ) const
+{
+ sal_Int32 nCompare = 0;
+ // seems that some ::std::sort() implementations pass the same index twice
+ if( nIndex1 != nIndex2 )
+ {
+ ScDPMembers* pMembers = rLevel.GetMembersObject();
+ ScDPMember* pMember1 = pMembers->getByIndex(nIndex1);
+ ScDPMember* pMember2 = pMembers->getByIndex(nIndex2);
+ nCompare = pMember1->Compare( *pMember2 );
+ }
+ return bAscending ? (nCompare < 0) : (nCompare > 0);
+}
+
+// -----------------------------------------------------------------------
+
+ScDPLevel::ScDPLevel( ScDPSource* pSrc, long nD, long nH, long nL ) :
+ pSource( pSrc ),
+ nDim( nD ),
+ nHier( nH ),
+ nLev( nL ),
+ pMembers( NULL ),
+ bShowEmpty( FALSE ),
+ aSortInfo( EMPTY_STRING, sal_True, sheet::DataPilotFieldSortMode::NAME ), // default: sort by name
+ nSortMeasure( 0 ),
+ nAutoMeasure( 0 ),
+ bEnableLayout( FALSE )
+{
+ //! hold pSource
+ // aSubTotals is empty
+}
+
+ScDPLevel::~ScDPLevel()
+{
+ //! release pSource
+
+ if ( pMembers )
+ pMembers->release(); // ref-counted
+}
+
+void ScDPLevel::EvaluateSortOrder()
+{
+ switch (aSortInfo.Mode)
+ {
+ case sheet::DataPilotFieldSortMode::DATA:
+ {
+ // find index of measure (index among data dimensions)
+
+ String aDataFieldName = aSortInfo.Field;
+ long nMeasureCount = pSource->GetDataDimensionCount();
+ for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++)
+ {
+ if ( pSource->GetDataDimName(nMeasure) == aDataFieldName )
+ {
+ nSortMeasure = nMeasure;
+ break;
+ }
+ }
+
+ //! error if not found?
+ }
+ break;
+ case sheet::DataPilotFieldSortMode::MANUAL:
+ case sheet::DataPilotFieldSortMode::NAME:
+ {
+ ScDPMembers* pLocalMembers = GetMembersObject();
+ long nCount = pLocalMembers->getCount();
+
+// DBG_ASSERT( aGlobalOrder.empty(), "sort twice?" );
+ aGlobalOrder.resize( nCount );
+ for (long nPos=0; nPos<nCount; nPos++)
+ aGlobalOrder[nPos] = nPos;
+
+ // allow manual or name (manual is always ascending)
+ BOOL bAscending = ( aSortInfo.Mode == sheet::DataPilotFieldSortMode::MANUAL || aSortInfo.IsAscending );
+ ScDPGlobalMembersOrder aComp( *this, bAscending );
+ ::std::sort( aGlobalOrder.begin(), aGlobalOrder.end(), aComp );
+ }
+ break;
+ }
+
+ if ( aAutoShowInfo.IsEnabled )
+ {
+ // find index of measure (index among data dimensions)
+
+ String aDataFieldName = aAutoShowInfo.DataField;
+ long nMeasureCount = pSource->GetDataDimensionCount();
+ for (long nMeasure=0; nMeasure<nMeasureCount; nMeasure++)
+ {
+ if ( pSource->GetDataDimName(nMeasure) == aDataFieldName )
+ {
+ nAutoMeasure = nMeasure;
+ break;
+ }
+ }
+
+ //! error if not found?
+ }
+}
+
+void ScDPLevel::SetEnableLayout( BOOL bSet )
+{
+ bEnableLayout = bSet;
+}
+
+ScDPMembers* ScDPLevel::GetMembersObject()
+{
+ if (!pMembers)
+ {
+ pMembers = new ScDPMembers( pSource, nDim, nHier, nLev );
+ pMembers->acquire(); // ref-counted
+ }
+ return pMembers;
+}
+
+uno::Reference<container::XNameAccess> SAL_CALL ScDPLevel::getMembers() throw(uno::RuntimeException)
+{
+ return GetMembersObject();
+}
+
+uno::Sequence<sheet::MemberResult> SAL_CALL ScDPLevel::getResults() throw(uno::RuntimeException)
+{
+ const uno::Sequence<sheet::MemberResult>* pRes = pSource->GetMemberResults( this );
+ if (pRes)
+ return *pRes;
+
+ return uno::Sequence<sheet::MemberResult>(0); //! Error?
+}
+
+::rtl::OUString SAL_CALL ScDPLevel::getName() throw(uno::RuntimeException)
+{
+ long nSrcDim = pSource->GetSourceDim( nDim );
+ if ( pSource->IsDateDimension( nSrcDim ) )
+ {
+ String aRet; //! globstr-ID !!!!
+
+ if ( nHier == SC_DAPI_HIERARCHY_QUARTER )
+ {
+ switch ( nLev )
+ {
+ case SC_DAPI_LEVEL_YEAR:
+ aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Year"));
+ break;
+ case SC_DAPI_LEVEL_QUARTER:
+ aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Quarter"));
+ break;
+ case SC_DAPI_LEVEL_MONTH:
+ aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Month"));
+ break;
+ case SC_DAPI_LEVEL_DAY:
+ aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Day"));
+ break;
+ default:
+ DBG_ERROR( "ScDPLevel::getName: unexpected level" );
+ break;
+ }
+ }
+ else if ( nHier == SC_DAPI_HIERARCHY_WEEK )
+ {
+ switch ( nLev )
+ {
+ case SC_DAPI_LEVEL_YEAR:
+ aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Year"));
+ break;
+ case SC_DAPI_LEVEL_WEEK:
+ aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Week"));
+ break;
+ case SC_DAPI_LEVEL_WEEKDAY:
+ aRet = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Weekday"));
+ break;
+ default:
+ DBG_ERROR( "ScDPLevel::getName: unexpected level" );
+ break;
+ }
+ }
+ if (aRet.Len())
+ return aRet;
+ }
+
+ return pSource->GetData()->getDimensionName( nSrcDim ); // (original) dimension name
+}
+
+void SAL_CALL ScDPLevel::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException)
+{
+ DBG_ERROR("not implemented"); //! exception?
+}
+
+uno::Sequence<sheet::GeneralFunction> ScDPLevel::getSubTotals() const
+{
+ //! separate functions for settings and evaluation?
+
+ long nSrcDim = pSource->GetSourceDim( nDim );
+ if ( !pSource->SubTotalAllowed( nSrcDim ) )
+ return uno::Sequence<sheet::GeneralFunction>(0);
+
+ return aSubTotals;
+}
+
+void ScDPLevel::setSubTotals(const uno::Sequence<sheet::GeneralFunction>& rNew)
+{
+ aSubTotals = rNew;
+ //! set "manual change" flag?
+}
+
+BOOL ScDPLevel::getShowEmpty() const
+{
+ return bShowEmpty;
+}
+
+void ScDPLevel::setShowEmpty(BOOL bSet)
+{
+ bShowEmpty = bSet;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPLevel::getPropertySetInfo()
+ throw(uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+
+ static SfxItemPropertyMap aDPLevelMap_Impl[] =
+ {
+ //! change type of AutoShow/Layout/Sorting to API struct when available
+ {MAP_CHAR_LEN(SC_UNO_AUTOSHOW), 0, &getCppuType((sheet::DataPilotFieldAutoShowInfo*)0), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_LAYOUT), 0, &getCppuType((sheet::DataPilotFieldLayoutInfo*)0), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_SHOWEMPT), 0, &getBooleanCppuType(), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_SORTING), 0, &getCppuType((sheet::DataPilotFieldSortInfo*)0), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_SUBTOTAL), 0, &getCppuType((uno::Sequence<sheet::GeneralFunction>*)0), 0, 0 },
+ {0,0,0,0,0,0}
+ };
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( aDPLevelMap_Impl );
+ return aRef;
+}
+
+void SAL_CALL ScDPLevel::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
+ throw(beans::UnknownPropertyException, beans::PropertyVetoException,
+ lang::IllegalArgumentException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ String aNameStr = aPropertyName;
+ if ( aNameStr.EqualsAscii( SC_UNO_SHOWEMPT ) )
+ setShowEmpty( lcl_GetBoolFromAny( aValue ) );
+ else if ( aNameStr.EqualsAscii( SC_UNO_SUBTOTAL ) )
+ {
+ uno::Sequence<sheet::GeneralFunction> aSeq;
+ if ( aValue >>= aSeq )
+ setSubTotals( aSeq );
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_SORTING ) )
+ aValue >>= aSortInfo;
+ else if ( aNameStr.EqualsAscii( SC_UNO_AUTOSHOW ) )
+ aValue >>= aAutoShowInfo;
+ else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) )
+ aValue >>= aLayoutInfo;
+ else
+ {
+ DBG_ERROR("unknown property");
+ //! THROW( UnknownPropertyException() );
+ }
+}
+
+uno::Any SAL_CALL ScDPLevel::getPropertyValue( const rtl::OUString& aPropertyName )
+ throw(beans::UnknownPropertyException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ uno::Any aRet;
+ String aNameStr = aPropertyName;
+ if ( aNameStr.EqualsAscii( SC_UNO_SHOWEMPT ) )
+ lcl_SetBoolInAny( aRet, getShowEmpty() );
+ else if ( aNameStr.EqualsAscii( SC_UNO_SUBTOTAL ) )
+ {
+ uno::Sequence<sheet::GeneralFunction> aSeq = getSubTotals(); //! avoid extra copy?
+ aRet <<= aSeq;
+ }
+ else if ( aNameStr.EqualsAscii( SC_UNO_SORTING ) )
+ aRet <<= aSortInfo;
+ else if ( aNameStr.EqualsAscii( SC_UNO_AUTOSHOW ) )
+ aRet <<= aAutoShowInfo;
+ else if ( aNameStr.EqualsAscii( SC_UNO_LAYOUT ) )
+ aRet <<= aLayoutInfo;
+ else
+ {
+ DBG_ERROR("unknown property");
+ //! THROW( UnknownPropertyException() );
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPLevel )
+
+// -----------------------------------------------------------------------
+
+USHORT lcl_GetFirstStringPos( const TypedScStrCollection& rColl )
+{
+ USHORT nPos = 0;
+ USHORT nCount = rColl.GetCount();
+ while ( nPos < nCount && !rColl[nPos]->IsStrData() )
+ ++nPos;
+ return nPos;
+}
+
+ScDPMembers::ScDPMembers( ScDPSource* pSrc, long nD, long nH, long nL ) :
+ pSource( pSrc ),
+ nDim( nD ),
+ nHier( nH ),
+ nLev( nL ),
+ ppMbrs( NULL )
+{
+ //! hold pSource
+
+ long nSrcDim = pSource->GetSourceDim( nDim );
+ if ( pSource->IsDataLayoutDimension(nSrcDim) )
+ nMbrCount = pSource->GetDataDimensionCount();
+ else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
+ {
+ nMbrCount = 0;
+ if ( nHier == SC_DAPI_HIERARCHY_QUARTER )
+ {
+ switch (nLev)
+ {
+ case SC_DAPI_LEVEL_YEAR:
+ {
+ const TypedScStrCollection& rStrings = pSource->GetData()->GetColumnEntries(nSrcDim);
+ USHORT nFirstString = lcl_GetFirstStringPos( rStrings );
+ if ( nFirstString > 0 )
+ {
+ double fFirstVal = rStrings[0]->GetValue();
+ double fLastVal = rStrings[nFirstString-1]->GetValue();
+
+ long nFirstYear = pSource->GetData()->GetDatePart(
+ (long)::rtl::math::approxFloor( fFirstVal ),
+ nHier, nLev );
+ long nLastYear = pSource->GetData()->GetDatePart(
+ (long)::rtl::math::approxFloor( fLastVal ),
+ nHier, nLev );
+
+ nMbrCount = nLastYear + 1 - nFirstYear;
+ }
+ else
+ nMbrCount = 0; // no values
+ }
+ break;
+ case SC_DAPI_LEVEL_QUARTER: nMbrCount = 4; break;
+ case SC_DAPI_LEVEL_MONTH: nMbrCount = 12; break;
+ case SC_DAPI_LEVEL_DAY: nMbrCount = 31; break;
+ default:
+ DBG_ERROR( "ScDPMembers::ScDPMembers: unexpected level" );
+ break;
+ }
+ }
+ else if ( nHier == SC_DAPI_HIERARCHY_WEEK )
+ {
+ switch (nLev)
+ {
+ case SC_DAPI_LEVEL_YEAR: nMbrCount = 1; break; //! get years from source
+ case SC_DAPI_LEVEL_WEEK: nMbrCount = 53; break;
+ case SC_DAPI_LEVEL_WEEKDAY: nMbrCount = 7; break;
+ default:
+ DBG_ERROR( "ScDPMembers::ScDPMembers: unexpected level" );
+ break;
+ }
+ }
+ }
+ else
+ {
+ // StringCollection is cached at TableData
+ const TypedScStrCollection& rStrings = pSource->GetData()->GetColumnEntries(nSrcDim);
+ nMbrCount = rStrings.GetCount();
+ }
+}
+
+ScDPMembers::~ScDPMembers()
+{
+ //! release pSource
+
+ if (ppMbrs)
+ {
+ for (long i=0; i<nMbrCount; i++)
+ if ( ppMbrs[i] )
+ ppMbrs[i]->release(); // ref-counted
+ delete[] ppMbrs;
+ }
+}
+
+// XNameAccess implementation using getCount/getByIndex
+
+sal_Int32 ScDPMembers::GetIndexFromName( const ::rtl::OUString& rName ) const
+{
+ if ( aHashMap.empty() )
+ {
+ // store the index for each name
+
+ sal_Int32 nCount = getCount();
+ for (sal_Int32 i=0; i<nCount; i++)
+ aHashMap[ getByIndex(i)->getName() ] = i;
+ }
+
+ ScDPMembersHashMap::const_iterator aIter = aHashMap.find( rName );
+ if ( aIter != aHashMap.end() )
+ return aIter->second; // found index
+ else
+ return -1; // not found
+}
+
+uno::Any SAL_CALL ScDPMembers::getByName( const rtl::OUString& aName )
+ throw(container::NoSuchElementException,
+ lang::WrappedTargetException, uno::RuntimeException)
+{
+ sal_Int32 nIndex = GetIndexFromName( aName );
+ if ( nIndex >= 0 )
+ {
+ uno::Reference<container::XNamed> xNamed = getByIndex(nIndex);
+ uno::Any aRet;
+ aRet <<= xNamed;
+ return aRet;
+ }
+
+ throw container::NoSuchElementException();
+// return uno::Any();
+}
+
+uno::Sequence<rtl::OUString> SAL_CALL ScDPMembers::getElementNames() throw(uno::RuntimeException)
+{
+ // Return list of names in sorted order,
+ // so it's displayed in that order in the field options dialog.
+ // Sorting is done at the level object (parent of this).
+
+ ScDPLevel* pLevel = pSource->GetDimensionsObject()->getByIndex(nDim)->
+ GetHierarchiesObject()->getByIndex(nHier)->GetLevelsObject()->getByIndex(nLev);
+ pLevel->EvaluateSortOrder();
+ const std::vector<sal_Int32>& rGlobalOrder = pLevel->GetGlobalOrder();
+ bool bSort = !rGlobalOrder.empty();
+
+ long nCount = getCount();
+ uno::Sequence<rtl::OUString> aSeq(nCount);
+ rtl::OUString* pArr = aSeq.getArray();
+ for (long i=0; i<nCount; i++)
+ pArr[i] = getByIndex(bSort ? rGlobalOrder[i] : i)->getName();
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScDPMembers::hasByName( const rtl::OUString& aName ) throw(uno::RuntimeException)
+{
+ return ( GetIndexFromName( aName ) >= 0 );
+}
+
+uno::Type SAL_CALL ScDPMembers::getElementType() throw(uno::RuntimeException)
+{
+ return getCppuType((uno::Reference<container::XNamed>*)0);
+}
+
+sal_Bool SAL_CALL ScDPMembers::hasElements() throw(uno::RuntimeException)
+{
+ return ( getCount() > 0 );
+}
+
+// end of XNameAccess implementation
+
+long ScDPMembers::getCount() const
+{
+ return nMbrCount;
+}
+
+long ScDPMembers::getMinMembers() const
+{
+ // used in lcl_CountMinMembers
+
+ long nVisCount = 0;
+ if ( ppMbrs )
+ {
+ for (long i=0; i<nMbrCount; i++)
+ {
+ // count only visible with details (default is true for both)
+ const ScDPMember* pMbr = ppMbrs[i];
+ if ( !pMbr || ( pMbr->getIsVisible() && pMbr->getShowDetails() ) )
+ ++nVisCount;
+ }
+ }
+ else
+ nVisCount = nMbrCount; // default for all
+
+ return nVisCount;
+}
+
+ScDPMember* ScDPMembers::getByIndex(long nIndex) const
+{
+ // result of GetColumnEntries must not change between ScDPMembers ctor
+ // and all calls to getByIndex
+
+ if ( nIndex >= 0 && nIndex < nMbrCount )
+ {
+ if ( !ppMbrs )
+ {
+ ((ScDPMembers*)this)->ppMbrs = new ScDPMember*[nMbrCount];
+ for (long i=0; i<nMbrCount; i++)
+ ppMbrs[i] = NULL;
+ }
+ if ( !ppMbrs[nIndex] )
+ {
+ ScDPMember* pNew;
+ long nSrcDim = pSource->GetSourceDim( nDim );
+ if ( pSource->IsDataLayoutDimension(nSrcDim) )
+ {
+ // empty name (never shown, not used for lookup)
+ pNew = new ScDPMember( pSource, nDim, nHier, nLev,
+ String(), 0.0, FALSE );
+ }
+ else if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) )
+ {
+ long nVal = 0;
+ String aName;
+
+ if ( nLev == SC_DAPI_LEVEL_YEAR ) // YEAR is in both hierarchies
+ {
+ //! cache year range here!
+
+ const TypedScStrCollection& rStrings = pSource->GetData()->GetColumnEntries(nSrcDim);
+ double fFirstVal = rStrings[0]->GetValue();
+ long nFirstYear = pSource->GetData()->GetDatePart(
+ (long)::rtl::math::approxFloor( fFirstVal ),
+ nHier, nLev );
+
+ nVal = nFirstYear + nIndex;
+ }
+ else if ( nHier == SC_DAPI_HIERARCHY_WEEK && nLev == SC_DAPI_LEVEL_WEEKDAY )
+ {
+ nVal = nIndex; // DayOfWeek is 0-based
+ aName = ScGlobal::pCalendar->getDisplayName(
+ ::com::sun::star::i18n::CalendarDisplayIndex::DAY,
+ sal::static_int_cast<sal_Int16>(nVal), 0 );
+ }
+ else if ( nHier == SC_DAPI_HIERARCHY_QUARTER && nLev == SC_DAPI_LEVEL_MONTH )
+ {
+ nVal = nIndex; // Month is 0-based
+ aName = ScGlobal::pCalendar->getDisplayName(
+ ::com::sun::star::i18n::CalendarDisplayIndex::MONTH,
+ sal::static_int_cast<sal_Int16>(nVal), 0 );
+ }
+ else
+ nVal = nIndex + 1; // Quarter, Day, Week are 1-based
+
+ if ( !aName.Len() )
+ aName = String::CreateFromInt32(nVal);
+
+ pNew = new ScDPMember( pSource, nDim, nHier, nLev, aName, nVal, TRUE );
+ }
+ else
+ {
+ const TypedScStrCollection& rStrings = pSource->GetData()->GetColumnEntries(nSrcDim);
+ const TypedStrData* pData = rStrings[(USHORT)nIndex];
+ pNew = new ScDPMember( pSource, nDim, nHier, nLev,
+ pData->GetString(), pData->GetValue(), !pData->IsStrData() );
+ }
+ pNew->acquire(); // ref-counted
+ ppMbrs[nIndex] = pNew;
+ }
+
+ return ppMbrs[nIndex];
+ }
+
+ return NULL; //! exception?
+}
+
+// -----------------------------------------------------------------------
+
+ScDPMember::ScDPMember( ScDPSource* pSrc, long nD, long nH, long nL,
+ const String& rN, double fV, BOOL bHV ) :
+ pSource( pSrc ),
+ nDim( nD ),
+ nHier( nH ),
+ nLev( nL ),
+ maData( rN, fV, bHV ),
+ nPosition( -1 ),
+ bVisible( TRUE ),
+ bShowDet( TRUE )
+{
+ //! hold pSource
+}
+
+ScDPMember::~ScDPMember()
+{
+ //! release pSource
+}
+
+BOOL ScDPMember::IsNamedItem( const ScDPItemData& r ) const
+{
+ long nSrcDim = pSource->GetSourceDim( nDim );
+ if ( nHier != SC_DAPI_HIERARCHY_FLAT && pSource->IsDateDimension( nSrcDim ) && r.bHasValue )
+ {
+ long nComp = pSource->GetData()->GetDatePart(
+ (long)::rtl::math::approxFloor( r.fValue ),
+ nHier, nLev );
+
+ // fValue is converted from integer, so simple comparison works
+ return nComp == maData.fValue;
+ }
+
+ return r.IsCaseInsEqual( maData );
+}
+
+sal_Int32 ScDPMember::Compare( const ScDPMember& rOther ) const
+{
+ if ( nPosition >= 0 )
+ {
+ if ( rOther.nPosition >= 0 )
+ {
+ DBG_ASSERT( nPosition != rOther.nPosition, "same position for two members" );
+ return ( nPosition < rOther.nPosition ) ? -1 : 1;
+ }
+ else
+ {
+ // only this has a position - members with specified positions come before those without
+ return -1;
+ }
+ }
+ else if ( rOther.nPosition >= 0 )
+ {
+ // only rOther has a position
+ return 1;
+ }
+
+ // no positions set - compare names
+ return ScDPItemData::Compare( maData, rOther.maData );
+}
+
+void ScDPMember::FillItemData( ScDPItemData& rData ) const
+{
+ //! handle date hierarchy...
+
+ rData = maData;
+}
+
+String ScDPMember::GetNameStr() const
+{
+ return maData.aString;
+}
+
+::rtl::OUString SAL_CALL ScDPMember::getName() throw(uno::RuntimeException)
+{
+ return maData.aString;
+}
+
+void SAL_CALL ScDPMember::setName( const ::rtl::OUString& /* rNewName */ ) throw(uno::RuntimeException)
+{
+ DBG_ERROR("not implemented"); //! exception?
+}
+
+BOOL ScDPMember::getIsVisible() const
+{
+ return bVisible;
+}
+
+void ScDPMember::setIsVisible(BOOL bSet)
+{
+ bVisible = bSet;
+ //! set "manual change" flag
+}
+
+BOOL ScDPMember::getShowDetails() const
+{
+ return bShowDet;
+}
+
+void ScDPMember::setShowDetails(BOOL bSet)
+{
+ bShowDet = bSet;
+ //! set "manual change" flag
+}
+
+sal_Int32 ScDPMember::getPosition() const
+{
+ return nPosition;
+}
+
+void ScDPMember::setPosition(sal_Int32 nNew)
+{
+ nPosition = nNew;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDPMember::getPropertySetInfo()
+ throw(uno::RuntimeException)
+{
+ ScUnoGuard aGuard;
+
+ static SfxItemPropertyMap aDPMemberMap_Impl[] =
+ {
+ {MAP_CHAR_LEN(SC_UNO_ISVISIBL), 0, &getBooleanCppuType(), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_POSITION), 0, &getCppuType((sal_Int32*)0), 0, 0 },
+ {MAP_CHAR_LEN(SC_UNO_SHOWDETA), 0, &getBooleanCppuType(), 0, 0 },
+ {0,0,0,0,0,0}
+ };
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( aDPMemberMap_Impl );
+ return aRef;
+}
+
+void SAL_CALL ScDPMember::setPropertyValue( const rtl::OUString& aPropertyName, const uno::Any& aValue )
+ throw(beans::UnknownPropertyException, beans::PropertyVetoException,
+ lang::IllegalArgumentException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ String aNameStr = aPropertyName;
+ if ( aNameStr.EqualsAscii( SC_UNO_ISVISIBL ) )
+ setIsVisible( lcl_GetBoolFromAny( aValue ) );
+ else if ( aNameStr.EqualsAscii( SC_UNO_SHOWDETA ) )
+ setShowDetails( lcl_GetBoolFromAny( aValue ) );
+ else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
+ {
+ sal_Int32 nInt = 0;
+ if (aValue >>= nInt)
+ setPosition( nInt );
+ }
+ else
+ {
+ DBG_ERROR("unknown property");
+ //! THROW( UnknownPropertyException() );
+ }
+}
+
+uno::Any SAL_CALL ScDPMember::getPropertyValue( const rtl::OUString& aPropertyName )
+ throw(beans::UnknownPropertyException, lang::WrappedTargetException,
+ uno::RuntimeException)
+{
+ uno::Any aRet;
+ String aNameStr = aPropertyName;
+ if ( aNameStr.EqualsAscii( SC_UNO_ISVISIBL ) )
+ lcl_SetBoolInAny( aRet, getIsVisible() );
+ else if ( aNameStr.EqualsAscii( SC_UNO_SHOWDETA ) )
+ lcl_SetBoolInAny( aRet, getShowDetails() );
+ else if ( aNameStr.EqualsAscii( SC_UNO_POSITION ) )
+ aRet <<= (sal_Int32) getPosition();
+ else
+ {
+ DBG_ERROR("unknown property");
+ //! THROW( UnknownPropertyException() );
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDPMember )
+
+
+
diff --git a/sc/source/core/data/drawpage.cxx b/sc/source/core/data/drawpage.cxx
new file mode 100644
index 000000000000..909d1e6111a9
--- /dev/null
+++ b/sc/source/core/data/drawpage.cxx
@@ -0,0 +1,68 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: drawpage.cxx,v $
+ * $Revision: 1.10 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <sfx2/objsh.hxx>
+
+#include "drawpage.hxx"
+#include "drwlayer.hxx"
+#include "document.hxx"
+#include "pageuno.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+// -----------------------------------------------------------------------
+
+ScDrawPage::ScDrawPage(ScDrawLayer& rNewModel, StarBASIC* pBasic, BOOL bMasterPage) :
+ FmFormPage(rNewModel, pBasic, bMasterPage)
+{
+ SetSize( Size( LONG_MAX, LONG_MAX ) );
+}
+
+// -----------------------------------------------------------------------
+
+__EXPORT ScDrawPage::~ScDrawPage()
+{
+}
+
+// -----------------------------------------------------------------------
+
+::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > ScDrawPage::createUnoPage()
+{
+ return static_cast<cppu::OWeakObject*>( new ScPageObj( this ) );
+}
+
+
diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
new file mode 100644
index 000000000000..5401c0e5327b
--- /dev/null
+++ b/sc/source/core/data/drwlayer.cxx
@@ -0,0 +1,2063 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: drwlayer.cxx,v $
+ * $Revision: 1.55.128.8 $
+ *
+ * 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 <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XVisualObject.hpp>
+#include <com/sun/star/embed/XClassifiedObject.hpp>
+#include <com/sun/star/embed/XComponentSupplier.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/eeitem.hxx>
+#include <svx/frmdiritem.hxx>
+#include <sot/exchange.hxx>
+#include <svx/objfac3d.hxx>
+#include <svx/xtable.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdocirc.hxx>
+#include <svx/svdoedge.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/unolingu.hxx>
+#include <svx/drawitem.hxx>
+#include <svx/fhgtitem.hxx>
+#include <svx/scriptspaceitem.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <sot/storage.hxx>
+#include <svtools/pathoptions.hxx>
+#include <svtools/itempool.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+
+#include "drwlayer.hxx"
+#include "drawpage.hxx"
+#include "global.hxx"
+#include "document.hxx"
+#include "rechead.hxx"
+#include "userdat.hxx"
+#include "markdata.hxx"
+#include "globstr.hrc"
+#include "scmod.hxx"
+#include "chartarr.hxx"
+#include "postit.hxx"
+#include "attrib.hxx"
+
+#define DET_ARROW_OFFSET 1000
+
+// Abstand zur naechsten Zelle beim Loeschen (bShrink), damit der Anker
+// immer an der richtigen Zelle angezeigt wird
+//#define SHRINK_DIST 3
+// und noch etwas mehr, damit das Objekt auch sichtbar in der Zelle liegt
+#define SHRINK_DIST 25
+
+#define SHRINK_DIST_TWIPS 15
+
+using namespace ::com::sun::star;
+
+// STATIC DATA -----------------------------------------------------------
+
+TYPEINIT1(ScTabDeletedHint, SfxHint);
+TYPEINIT1(ScTabSizeChangedHint, SfxHint);
+
+static ScDrawObjFactory* pFac = NULL;
+static E3dObjFactory* pF3d = NULL;
+static USHORT nInst = 0;
+
+SfxObjectShell* ScDrawLayer::pGlobalDrawPersist = NULL;
+//REMOVE SvPersist* ScDrawLayer::pGlobalDrawPersist = NULL;
+
+BOOL bDrawIsInUndo = FALSE; //! Member
+
+// -----------------------------------------------------------------------
+
+ScUndoObjData::ScUndoObjData( SdrObject* pObjP, const ScAddress& rOS, const ScAddress& rOE,
+ const ScAddress& rNS, const ScAddress& rNE ) :
+ SdrUndoObj( *pObjP ),
+ aOldStt( rOS ),
+ aOldEnd( rOE ),
+ aNewStt( rNS ),
+ aNewEnd( rNE )
+{
+}
+
+__EXPORT ScUndoObjData::~ScUndoObjData()
+{
+}
+
+void ScUndoObjData::Undo()
+{
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
+ DBG_ASSERT(pData,"ScUndoObjData: Daten nicht da");
+ if (pData)
+ {
+ pData->maStart = aOldStt;
+ pData->maEnd = aOldEnd;
+ }
+}
+
+void __EXPORT ScUndoObjData::Redo()
+{
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
+ DBG_ASSERT(pData,"ScUndoObjData: Daten nicht da");
+ if (pData)
+ {
+ pData->maStart = aNewStt;
+ pData->maEnd = aNewEnd;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ScTabDeletedHint::ScTabDeletedHint( SCTAB nTabNo ) :
+ nTab( nTabNo )
+{
+}
+
+__EXPORT ScTabDeletedHint::~ScTabDeletedHint()
+{
+}
+
+ScTabSizeChangedHint::ScTabSizeChangedHint( SCTAB nTabNo ) :
+ nTab( nTabNo )
+{
+}
+
+__EXPORT ScTabSizeChangedHint::~ScTabSizeChangedHint()
+{
+}
+
+// -----------------------------------------------------------------------
+
+#define MAXMM 10000000
+
+inline void TwipsToMM( long& nVal )
+{
+ nVal = (long) ( nVal * HMM_PER_TWIPS );
+}
+
+inline void ReverseTwipsToMM( long& nVal )
+{
+ // reverse the effect of TwipsToMM - round up here (add 1)
+
+ nVal = ((long) ( nVal / HMM_PER_TWIPS )) + 1;
+}
+
+void lcl_TwipsToMM( Point& rPoint )
+{
+ TwipsToMM( rPoint.X() );
+ TwipsToMM( rPoint.Y() );
+}
+
+void lcl_ReverseTwipsToMM( Point& rPoint )
+{
+ ReverseTwipsToMM( rPoint.X() );
+ ReverseTwipsToMM( rPoint.Y() );
+}
+
+void lcl_ReverseTwipsToMM( Rectangle& rRect )
+{
+ ReverseTwipsToMM( rRect.Left() );
+ ReverseTwipsToMM( rRect.Right() );
+ ReverseTwipsToMM( rRect.Top() );
+ ReverseTwipsToMM( rRect.Bottom() );
+}
+
+// -----------------------------------------------------------------------
+
+
+ScDrawLayer::ScDrawLayer( ScDocument* pDocument, const String& rName ) :
+ FmFormModel( SvtPathOptions().GetPalettePath(),
+ NULL, // SfxItemPool* Pool
+ pGlobalDrawPersist ?
+ pGlobalDrawPersist :
+ ( pDocument ? pDocument->GetDocumentShell() : NULL ),
+ TRUE ), // bUseExtColorTable (is set below)
+ aName( rName ),
+ pDoc( pDocument ),
+ pUndoGroup( NULL ),
+ bRecording( FALSE ),
+ bAdjustEnabled( TRUE ),
+ bHyphenatorSet( FALSE )
+{
+ pGlobalDrawPersist = NULL; // nur einmal benutzen
+
+ SfxObjectShell* pObjSh = pDocument ? pDocument->GetDocumentShell() : NULL;
+ if ( pObjSh )
+ {
+ SetObjectShell( pObjSh );
+
+ // set color table
+ SvxColorTableItem* pColItem = (SvxColorTableItem*) pObjSh->GetItem( SID_COLOR_TABLE );
+ XColorTable* pXCol = pColItem ? pColItem->GetColorTable() : XColorTable::GetStdColorTable();
+ SetColorTable( pXCol );
+ }
+ else
+ SetColorTable( XColorTable::GetStdColorTable() );
+
+ SetSwapGraphics(TRUE);
+// SetSwapAsynchron(TRUE); // an der View
+
+ SetScaleUnit(MAP_100TH_MM);
+ SfxItemPool& rPool = GetItemPool();
+ rPool.SetDefaultMetric(SFX_MAPUNIT_100TH_MM);
+ SvxFrameDirectionItem aModeItem( FRMDIR_ENVIRONMENT, EE_PARA_WRITINGDIR );
+ rPool.SetPoolDefaultItem( aModeItem );
+
+ // #i33700#
+ // Set shadow distance defaults as PoolDefaultItems. Details see bug.
+ rPool.SetPoolDefaultItem(SdrShadowXDistItem(300));
+ rPool.SetPoolDefaultItem(SdrShadowYDistItem(300));
+
+ // #111216# default for script spacing depends on locale, see SdDrawDocument ctor in sd
+ LanguageType eOfficeLanguage = Application::GetSettings().GetLanguage();
+ if ( eOfficeLanguage == LANGUAGE_KOREAN || eOfficeLanguage == LANGUAGE_KOREAN_JOHAB ||
+ eOfficeLanguage == LANGUAGE_JAPANESE )
+ {
+ // secondary is edit engine pool
+ rPool.GetSecondaryPool()->SetPoolDefaultItem( SvxScriptSpaceItem( FALSE, EE_PARA_ASIANCJKSPACING ) );
+ }
+
+ rPool.FreezeIdRanges(); // the pool is also used directly
+
+ SdrLayerAdmin& rAdmin = GetLayerAdmin();
+ rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("vorne")), SC_LAYER_FRONT);
+ rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("hinten")), SC_LAYER_BACK);
+ rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("intern")), SC_LAYER_INTERN);
+ rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("Controls")), SC_LAYER_CONTROLS);
+ rAdmin.NewLayer(String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("hidden")), SC_LAYER_HIDDEN);
+ // "Controls" is new - must also be created when loading
+
+ // Link fuer URL-Fields setzen
+ ScModule* pScMod = SC_MOD();
+ Outliner& rOutliner = GetDrawOutliner();
+ rOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
+
+ Outliner& rHitOutliner = GetHitTestOutliner();
+ rHitOutliner.SetCalcFieldValueHdl( LINK( pScMod, ScModule, CalcFieldValueHdl ) );
+
+ // #95129# SJ: set FontHeight pool defaults without changing static SdrEngineDefaults
+ SfxItemPool* pOutlinerPool = rOutliner.GetEditTextObjectPool();
+ if ( pOutlinerPool )
+ pItemPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT )); // 12Pt
+ SfxItemPool* pHitOutlinerPool = rHitOutliner.GetEditTextObjectPool();
+ if ( pHitOutlinerPool )
+ pHitOutlinerPool->SetPoolDefaultItem(SvxFontHeightItem( 423, 100, EE_CHAR_FONTHEIGHT )); // 12Pt
+
+ // URL-Buttons haben keinen Handler mehr, machen alles selber
+
+ if( !nInst++ )
+ {
+ pFac = new ScDrawObjFactory;
+ pF3d = new E3dObjFactory;
+ }
+}
+
+__EXPORT ScDrawLayer::~ScDrawLayer()
+{
+ Broadcast(SdrHint(HINT_MODELCLEARED));
+
+ // #116168#
+ //Clear();
+ ClearModel(sal_True);
+
+ delete pUndoGroup;
+ if( !--nInst )
+ {
+ delete pFac, pFac = NULL;
+ delete pF3d, pF3d = NULL;
+ }
+}
+
+void ScDrawLayer::UseHyphenator()
+{
+ if (!bHyphenatorSet)
+ {
+ com::sun::star::uno::Reference< com::sun::star::linguistic2::XHyphenator >
+ xHyphenator = LinguMgr::GetHyphenator();
+
+ GetDrawOutliner().SetHyphenator( xHyphenator );
+ GetHitTestOutliner().SetHyphenator( xHyphenator );
+
+ bHyphenatorSet = TRUE;
+ }
+}
+
+SdrPage* __EXPORT ScDrawLayer::AllocPage(FASTBOOL bMasterPage)
+{
+ // don't create basic until it is needed
+ StarBASIC* pBasic = NULL;
+ ScDrawPage* pPage = new ScDrawPage( *this, pBasic, sal::static_int_cast<BOOL>(bMasterPage) );
+ return pPage;
+}
+
+BOOL ScDrawLayer::HasObjects() const
+{
+ BOOL bFound = FALSE;
+
+ USHORT nCount = GetPageCount();
+ for (USHORT i=0; i<nCount && !bFound; i++)
+ if (GetPage(i)->GetObjCount())
+ bFound = TRUE;
+
+ return bFound;
+}
+
+void ScDrawLayer::UpdateBasic()
+{
+ // don't create basic until it is needed
+ //! remove this method?
+}
+
+SdrModel* __EXPORT ScDrawLayer::AllocModel() const
+{
+ // #103849# Allocated model (for clipboard etc) must not have a pointer
+ // to the original model's document, pass NULL as document:
+
+ return new ScDrawLayer( NULL, aName );
+}
+
+Window* __EXPORT ScDrawLayer::GetCurDocViewWin()
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::GetCurDocViewWin without document" );
+ if ( !pDoc )
+ return NULL;
+
+ SfxViewShell* pViewSh = SfxViewShell::Current();
+ SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
+
+ if (pViewSh && pViewSh->GetObjectShell() == pObjSh)
+ return pViewSh->GetWindow();
+
+ return NULL;
+}
+
+BOOL ScDrawLayer::ScAddPage( SCTAB nTab )
+{
+ if (bDrawIsInUndo)
+ return FALSE; // not inserted
+
+ ScDrawPage* pPage = (ScDrawPage*)AllocPage( FALSE );
+ InsertPage(pPage, static_cast<sal_uInt16>(nTab));
+ if (bRecording)
+ AddCalcUndo(new SdrUndoNewPage(*pPage));
+
+ return TRUE; // inserted
+}
+
+void ScDrawLayer::ScRemovePage( SCTAB nTab )
+{
+ if (bDrawIsInUndo)
+ return;
+
+ Broadcast( ScTabDeletedHint( nTab ) );
+ if (bRecording)
+ {
+ SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
+ AddCalcUndo(new SdrUndoDelPage(*pPage)); // Undo-Action wird Owner der Page
+ RemovePage( static_cast<sal_uInt16>(nTab) ); // nur austragen, nicht loeschen
+ }
+ else
+ DeletePage( static_cast<sal_uInt16>(nTab) ); // einfach weg damit
+}
+
+void ScDrawLayer::ScRenamePage( SCTAB nTab, const String& rNewName )
+{
+ ScDrawPage* pPage = (ScDrawPage*) GetPage(static_cast<sal_uInt16>(nTab));
+ if (pPage)
+ pPage->SetName(rNewName);
+}
+
+void ScDrawLayer::ScMovePage( USHORT nOldPos, USHORT nNewPos )
+{
+ MovePage( nOldPos, nNewPos );
+}
+
+void ScDrawLayer::ScCopyPage( USHORT nOldPos, USHORT nNewPos, BOOL bAlloc )
+{
+ //! remove argument bAlloc (always FALSE)
+
+ if (bDrawIsInUndo)
+ return;
+
+ SdrPage* pOldPage = GetPage(nOldPos);
+ SdrPage* pNewPage = bAlloc ? AllocPage(FALSE) : GetPage(nNewPos);
+
+ // kopieren
+
+ if (pOldPage && pNewPage)
+ {
+ SdrObjListIter aIter( *pOldPage, IM_FLAT );
+ SdrObject* pOldObject = aIter.Next();
+ while (pOldObject)
+ {
+ // #116235#
+ SdrObject* pNewObject = pOldObject->Clone();
+ //SdrObject* pNewObject = pOldObject->Clone( pNewPage, this );
+ pNewObject->SetModel(this);
+ pNewObject->SetPage(pNewPage);
+
+ pNewObject->NbcMove(Size(0,0));
+ pNewPage->InsertObject( pNewObject );
+ if (bRecording)
+ AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) );
+
+ pOldObject = aIter.Next();
+ }
+ }
+
+ if (bAlloc)
+ InsertPage(pNewPage, nNewPos);
+}
+
+inline BOOL IsInBlock( const ScAddress& rPos, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2 )
+{
+ return rPos.Col() >= nCol1 && rPos.Col() <= nCol2 &&
+ rPos.Row() >= nRow1 && rPos.Row() <= nRow2;
+}
+
+void ScDrawLayer::MoveCells( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
+ SCsCOL nDx,SCsROW nDy )
+{
+ SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page nicht gefunden");
+ if (!pPage)
+ return;
+
+ BOOL bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
+
+ ULONG nCount = pPage->GetObjCount();
+ for ( ULONG i = 0; i < nCount; i++ )
+ {
+ SdrObject* pObj = pPage->GetObj( i );
+ ScDrawObjData* pData = GetObjDataTab( pObj, nTab );
+ if( pData )
+ {
+ const ScAddress aOldStt = pData->maStart;
+ const ScAddress aOldEnd = pData->maEnd;
+ BOOL bChange = FALSE;
+ if ( aOldStt.IsValid() && IsInBlock( aOldStt, nCol1,nRow1, nCol2,nRow2 ) )
+ {
+ pData->maStart.IncCol( nDx );
+ pData->maStart.IncRow( nDy );
+ bChange = TRUE;
+ }
+ if ( aOldEnd.IsValid() && IsInBlock( aOldEnd, nCol1,nRow1, nCol2,nRow2 ) )
+ {
+ pData->maEnd.IncCol( nDx );
+ pData->maEnd.IncRow( nDy );
+ bChange = TRUE;
+ }
+ if (bChange)
+ {
+ if ( pObj->ISA( SdrRectObj ) && pData->maStart.IsValid() && pData->maEnd.IsValid() )
+ pData->maStart.PutInOrder( pData->maEnd );
+ AddCalcUndo( new ScUndoObjData( pObj, aOldStt, aOldEnd, pData->maStart, pData->maEnd ) );
+ RecalcPos( pObj, *pData, aOldStt, aOldEnd, bNegativePage );
+ }
+ }
+ }
+}
+
+void ScDrawLayer::SetPageSize( USHORT nPageNo, const Size& rSize )
+{
+ SdrPage* pPage = GetPage(nPageNo);
+ if (pPage)
+ {
+ if ( rSize != pPage->GetSize() )
+ {
+ pPage->SetSize( rSize );
+ Broadcast( ScTabSizeChangedHint( static_cast<SCTAB>(nPageNo) ) ); // SetWorkArea() an den Views
+ }
+
+ // Detektivlinien umsetzen (an neue Hoehen/Breiten anpassen)
+ // auch wenn Groesse gleich geblieben ist
+ // (einzelne Zeilen/Spalten koennen geaendert sein)
+
+ BOOL bNegativePage = pDoc && pDoc->IsNegativePage( static_cast<SCTAB>(nPageNo) );
+
+ ULONG nCount = pPage->GetObjCount();
+ for ( ULONG i = 0; i < nCount; i++ )
+ {
+ SdrObject* pObj = pPage->GetObj( i );
+ ScDrawObjData* pData = GetObjDataTab( pObj, static_cast<SCTAB>(nPageNo) );
+ if( pData )
+ RecalcPos( pObj, *pData, pData->maStart, pData->maEnd, bNegativePage );
+ }
+ }
+}
+
+void ScDrawLayer::RecalcPos( SdrObject* pObj, const ScDrawObjData& rData,
+ const ScAddress& rOldStart, const ScAddress& /*rOldEnd*/, bool bNegativePage )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::RecalcPos - missing document" );
+ if( !pDoc )
+ return;
+
+ if( rData.mbNote )
+ {
+ /* #i63671# while inserting/deleting cells/rows/columns: note has
+ not been moved yet in document, get it from old position. */
+ DBG_ASSERT( rOldStart.IsValid(), "ScDrawLayer::RecalcPos - invalid position for cell note" );
+ /* When inside an undo action, there may be pending note captions
+ where cell note is already deleted. The caption will be deleted
+ later with drawing undo. */
+ if( ScPostIt* pNote = pDoc->GetNote( rOldStart ) )
+ pNote->UpdateCaptionPos( rData.maStart );
+ return;
+ }
+
+ bool bValid1 = rData.maStart.IsValid();
+ SCCOL nCol1 = rData.maStart.Col();
+ SCROW nRow1 = rData.maStart.Row();
+ SCTAB nTab1 = rData.maStart.Tab();
+ bool bValid2 = rData.maEnd.IsValid();
+ SCCOL nCol2 = rData.maEnd.Col();
+ SCROW nRow2 = rData.maEnd.Row();
+ SCTAB nTab2 = rData.maEnd.Tab();
+
+ // validation circle
+ bool bCircle = pObj->ISA( SdrCircObj );
+ // detective arrow
+ bool bArrow = pObj->IsPolyObj() && (pObj->GetPointCount() == 2);
+
+ if( bCircle )
+ {
+ Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
+ TwipsToMM( aPos.X() );
+ TwipsToMM( aPos.Y() );
+
+ // Berechnung und Werte wie in detfunc.cxx
+
+ Size aSize( (long)(pDoc->GetColWidth( nCol1, nTab1 ) * HMM_PER_TWIPS),
+ (long)(pDoc->GetRowHeight( nRow1, nTab1 ) * HMM_PER_TWIPS) );
+ Rectangle aRect( aPos, aSize );
+ aRect.Left() -= 250;
+ aRect.Right() += 250;
+ aRect.Top() -= 70;
+ aRect.Bottom() += 70;
+ if ( bNegativePage )
+ MirrorRectRTL( aRect );
+
+ if ( pObj->GetLogicRect() != aRect )
+ {
+ if (bRecording)
+ AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
+ pObj->SetLogicRect(aRect);
+ }
+ }
+ else if( bArrow )
+ {
+ //! nicht mehrere Undos fuer ein Objekt erzeugen (hinteres kann dann weggelassen werden)
+
+ if( bValid1 )
+ {
+ Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
+ if( (pDoc->GetColFlags( nCol1, nTab1 ) & CR_HIDDEN) == 0 )
+ aPos.X() += pDoc->GetColWidth( nCol1, nTab1 ) / 4;
+ if( (pDoc->GetRowFlags( nRow1, nTab1 ) & CR_HIDDEN) == 0 )
+ aPos.Y() += pDoc->GetRowHeight( nRow1, nTab1 ) / 2;
+ TwipsToMM( aPos.X() );
+ TwipsToMM( aPos.Y() );
+ Point aStartPos = aPos;
+ if ( bNegativePage )
+ aStartPos.X() = -aStartPos.X(); // don't modify aPos - used below
+ if ( pObj->GetPoint( 0 ) != aStartPos )
+ {
+ if (bRecording)
+ AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
+ pObj->SetPoint( aStartPos, 0 );
+ }
+
+ if( !bValid2 )
+ {
+ Point aEndPos( aPos.X() + DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
+ if (aEndPos.Y() < 0)
+ aEndPos.Y() += (2 * DET_ARROW_OFFSET);
+ if ( bNegativePage )
+ aEndPos.X() = -aEndPos.X();
+ if ( pObj->GetPoint( 1 ) != aEndPos )
+ {
+ if (bRecording)
+ AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
+ pObj->SetPoint( aEndPos, 1 );
+ }
+ }
+ }
+ if( bValid2 )
+ {
+ Point aPos( pDoc->GetColOffset( nCol2, nTab2 ), pDoc->GetRowOffset( nRow2, nTab2 ) );
+ if( (pDoc->GetColFlags( nCol2, nTab2 ) & CR_HIDDEN) == 0 )
+ aPos.X() += pDoc->GetColWidth( nCol2, nTab2 ) / 4;
+ if( (pDoc->GetRowFlags( nRow2, nTab2 ) & CR_HIDDEN) == 0 )
+ aPos.Y() += pDoc->GetRowHeight( nRow2, nTab2 ) / 2;
+ TwipsToMM( aPos.X() );
+ TwipsToMM( aPos.Y() );
+ Point aEndPos = aPos;
+ if ( bNegativePage )
+ aEndPos.X() = -aEndPos.X(); // don't modify aPos - used below
+ if ( pObj->GetPoint( 1 ) != aEndPos )
+ {
+ if (bRecording)
+ AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
+ pObj->SetPoint( aEndPos, 1 );
+ }
+
+ if( !bValid1 )
+ {
+ Point aStartPos( aPos.X() - DET_ARROW_OFFSET, aPos.Y() - DET_ARROW_OFFSET );
+ if (aStartPos.X() < 0)
+ aStartPos.X() += (2 * DET_ARROW_OFFSET);
+ if (aStartPos.Y() < 0)
+ aStartPos.Y() += (2 * DET_ARROW_OFFSET);
+ if ( bNegativePage )
+ aStartPos.X() = -aStartPos.X();
+ if ( pObj->GetPoint( 0 ) != aStartPos )
+ {
+ if (bRecording)
+ AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
+ pObj->SetPoint( aStartPos, 0 );
+ }
+ }
+ }
+ }
+ else // Referenz-Rahmen
+ {
+ DBG_ASSERT( bValid1, "ScDrawLayer::RecalcPos - invalid start position" );
+ Point aPos( pDoc->GetColOffset( nCol1, nTab1 ), pDoc->GetRowOffset( nRow1, nTab1 ) );
+ TwipsToMM( aPos.X() );
+ TwipsToMM( aPos.Y() );
+
+ if( bValid2 )
+ {
+ Point aEnd( pDoc->GetColOffset( nCol2 + 1, nTab2 ), pDoc->GetRowOffset( nRow2 + 1, nTab2 ) );
+ TwipsToMM( aEnd.X() );
+ TwipsToMM( aEnd.Y() );
+
+ Rectangle aNew( aPos, aEnd );
+ if ( bNegativePage )
+ MirrorRectRTL( aNew );
+ if ( pObj->GetLogicRect() != aNew )
+ {
+ if (bRecording)
+ AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
+ pObj->SetLogicRect(aNew);
+ }
+ }
+ else
+ {
+ if ( bNegativePage )
+ aPos.X() = -aPos.X();
+ if ( pObj->GetRelativePos() != aPos )
+ {
+ if (bRecording)
+ AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
+ pObj->SetRelativePos( aPos );
+ }
+ }
+ }
+}
+
+BOOL ScDrawLayer::GetPrintArea( ScRange& rRange, BOOL bSetHor, BOOL bSetVer ) const
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::GetPrintArea without document" );
+ if ( !pDoc )
+ return FALSE;
+
+ SCTAB nTab = rRange.aStart.Tab();
+ DBG_ASSERT( rRange.aEnd.Tab() == nTab, "GetPrintArea: Tab unterschiedlich" );
+
+ BOOL bNegativePage = pDoc->IsNegativePage( nTab );
+
+ BOOL bAny = FALSE;
+ long nEndX = 0;
+ long nEndY = 0;
+ long nStartX = LONG_MAX;
+ long nStartY = LONG_MAX;
+
+ // Grenzen ausrechnen
+
+ if (!bSetHor)
+ {
+ nStartX = 0;
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCCOL i;
+ for (i=0; i<nStartCol; i++)
+ nStartX +=pDoc->GetColWidth(i,nTab);
+ nEndX = nStartX;
+ SCCOL nEndCol = rRange.aEnd.Col();
+ for (i=nStartCol; i<=nEndCol; i++)
+ nEndX += pDoc->GetColWidth(i,nTab);
+ nStartX = (long)(nStartX * HMM_PER_TWIPS);
+ nEndX = (long)(nEndX * HMM_PER_TWIPS);
+ }
+ if (!bSetVer)
+ {
+ nStartY = pDoc->FastGetRowHeight( 0, rRange.aStart.Row()-1, nTab);
+ nEndY = nStartY + pDoc->FastGetRowHeight( rRange.aStart.Row(),
+ rRange.aEnd.Row(), nTab);
+ nStartY = (long)(nStartY * HMM_PER_TWIPS);
+ nEndY = (long)(nEndY * HMM_PER_TWIPS);
+ }
+
+ if ( bNegativePage )
+ {
+ nStartX = -nStartX; // positions are negative, swap start/end so the same comparisons work
+ nEndX = -nEndX;
+ ::std::swap( nStartX, nEndX );
+ }
+
+ const SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page nicht gefunden");
+ if (pPage)
+ {
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ //! Flags (ausgeblendet?) testen
+
+ Rectangle aObjRect = pObject->GetCurrentBoundRect();
+ BOOL bFit = TRUE;
+ if ( !bSetHor && ( aObjRect.Right() < nStartX || aObjRect.Left() > nEndX ) )
+ bFit = FALSE;
+ if ( !bSetVer && ( aObjRect.Bottom() < nStartY || aObjRect.Top() > nEndY ) )
+ bFit = FALSE;
+ if ( bFit )
+ {
+ if (bSetHor)
+ {
+ if (aObjRect.Left() < nStartX) nStartX = aObjRect.Left();
+ if (aObjRect.Right() > nEndX) nEndX = aObjRect.Right();
+ }
+ if (bSetVer)
+ {
+ if (aObjRect.Top() < nStartY) nStartY = aObjRect.Top();
+ if (aObjRect.Bottom() > nEndY) nEndY = aObjRect.Bottom();
+ }
+ bAny = TRUE;
+ }
+
+ pObject = aIter.Next();
+ }
+ }
+
+ if ( bNegativePage )
+ {
+ nStartX = -nStartX; // reverse transformation, so the same cell address calculation works
+ nEndX = -nEndX;
+ ::std::swap( nStartX, nEndX );
+ }
+
+ if (bAny)
+ {
+ DBG_ASSERT( nStartX<=nEndX && nStartY<=nEndY, "Start/End falsch in ScDrawLayer::GetPrintArea" );
+
+ if (bSetHor)
+ {
+ nStartX = (long) (nStartX / HMM_PER_TWIPS);
+ nEndX = (long) (nEndX / HMM_PER_TWIPS);
+ long nWidth;
+ SCCOL i;
+
+ nWidth = 0;
+ for (i=0; i<=MAXCOL && nWidth<=nStartX; i++)
+ nWidth += pDoc->GetColWidth(i,nTab);
+ rRange.aStart.SetCol( i>0 ? (i-1) : 0 );
+
+ nWidth = 0;
+ for (i=0; i<=MAXCOL && nWidth<=nEndX; i++) //! bei Start anfangen
+ nWidth += pDoc->GetColWidth(i,nTab);
+ rRange.aEnd.SetCol( i>0 ? (i-1) : 0 );
+ }
+
+ if (bSetVer)
+ {
+ nStartY = (long) (nStartY / HMM_PER_TWIPS);
+ nEndY = (long) (nEndY / HMM_PER_TWIPS);
+ SCROW nRow = pDoc->FastGetRowForHeight( nTab, nStartY);
+ rRange.aStart.SetRow( nRow>0 ? (nRow-1) : 0);
+ nRow = pDoc->FastGetRowForHeight( nTab, nEndY);
+ rRange.aEnd.SetRow( nRow == MAXROW ? MAXROW :
+ (nRow>0 ? (nRow-1) : 0));
+ }
+ }
+ else
+ {
+ if (bSetHor)
+ {
+ rRange.aStart.SetCol(0);
+ rRange.aEnd.SetCol(0);
+ }
+ if (bSetVer)
+ {
+ rRange.aStart.SetRow(0);
+ rRange.aEnd.SetRow(0);
+ }
+ }
+ return bAny;
+}
+
+void ScDrawLayer::AddCalcUndo( SdrUndoAction* pUndo )
+{
+ if (bRecording)
+ {
+ if (!pUndoGroup)
+ pUndoGroup = new SdrUndoGroup(*this);
+
+ pUndoGroup->AddAction( pUndo );
+ }
+ else
+ delete pUndo;
+}
+
+void ScDrawLayer::BeginCalcUndo()
+{
+//! DBG_ASSERT( !bRecording, "BeginCalcUndo ohne GetCalcUndo" );
+
+ DELETEZ(pUndoGroup);
+ bRecording = TRUE;
+}
+
+SdrUndoGroup* ScDrawLayer::GetCalcUndo()
+{
+//! DBG_ASSERT( bRecording, "GetCalcUndo ohne BeginCalcUndo" );
+
+ SdrUndoGroup* pRet = pUndoGroup;
+ pUndoGroup = NULL;
+ bRecording = FALSE;
+ return pRet;
+}
+
+// MoveAreaTwips: all measures are kept in twips
+void ScDrawLayer::MoveAreaTwips( SCTAB nTab, const Rectangle& rArea,
+ const Point& rMove, const Point& rTopLeft )
+{
+ if (!rMove.X() && !rMove.Y())
+ return; // nix
+
+ SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page nicht gefunden");
+ if (!pPage)
+ return;
+
+ BOOL bNegativePage = pDoc && pDoc->IsNegativePage( nTab );
+
+ // fuer Shrinking!
+ Rectangle aNew( rArea );
+ BOOL bShrink = FALSE;
+ if ( rMove.X() < 0 || rMove.Y() < 0 ) // verkleinern
+ {
+ if ( rTopLeft != rArea.TopLeft() ) // sind gleich beim Verschieben von Zellen
+ {
+ bShrink = TRUE;
+ aNew.Left() = rTopLeft.X();
+ aNew.Top() = rTopLeft.Y();
+ }
+ }
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if( GetAnchor( pObject ) == SCA_CELL )
+ {
+ if ( GetObjData( pObject ) ) // Detektiv-Pfeil ?
+ {
+ // hier nichts
+ }
+ else if ( pObject->ISA( SdrEdgeObj ) ) // Verbinder?
+ {
+ // hier auch nichts
+ //! nicht verbundene Enden wie bei Linien (s.u.) behandeln?
+ }
+ else if ( pObject->IsPolyObj() && pObject->GetPointCount()==2 )
+ {
+ for (USHORT i=0; i<2; i++)
+ {
+ BOOL bMoved = FALSE;
+ Point aPoint = pObject->GetPoint(i);
+ lcl_ReverseTwipsToMM( aPoint );
+ if (rArea.IsInside(aPoint))
+ {
+ aPoint += rMove; bMoved = TRUE;
+ }
+ else if (bShrink && aNew.IsInside(aPoint))
+ {
+ // Punkt ist in betroffener Zelle - Test auf geloeschten Bereich
+ if ( rMove.X() && aPoint.X() >= rArea.Left() + rMove.X() )
+ {
+ aPoint.X() = rArea.Left() + rMove.X() - SHRINK_DIST_TWIPS;
+ if ( aPoint.X() < 0 ) aPoint.X() = 0;
+ bMoved = TRUE;
+ }
+ if ( rMove.Y() && aPoint.Y() >= rArea.Top() + rMove.Y() )
+ {
+ aPoint.Y() = rArea.Top() + rMove.Y() - SHRINK_DIST_TWIPS;
+ if ( aPoint.Y() < 0 ) aPoint.Y() = 0;
+ bMoved = TRUE;
+ }
+ }
+ if( bMoved )
+ {
+ AddCalcUndo( new SdrUndoGeoObj( *pObject ) );
+ lcl_TwipsToMM( aPoint );
+ pObject->SetPoint( aPoint, i );
+ }
+ }
+ }
+ else
+ {
+ Rectangle aObjRect = pObject->GetLogicRect();
+ // aOldMMPos: not converted, millimeters
+ Point aOldMMPos = bNegativePage ? aObjRect.TopRight() : aObjRect.TopLeft();
+ lcl_ReverseTwipsToMM( aObjRect );
+ Point aTopLeft = bNegativePage ? aObjRect.TopRight() : aObjRect.TopLeft(); // logical left
+ Size aMoveSize;
+ BOOL bDoMove = FALSE;
+ if (rArea.IsInside(aTopLeft))
+ {
+ aMoveSize = Size(rMove.X(),rMove.Y());
+ bDoMove = TRUE;
+ }
+ else if (bShrink && aNew.IsInside(aTopLeft))
+ {
+ // Position ist in betroffener Zelle - Test auf geloeschten Bereich
+ if ( rMove.X() && aTopLeft.X() >= rArea.Left() + rMove.X() )
+ {
+ aMoveSize.Width() = rArea.Left() + rMove.X() - SHRINK_DIST - aTopLeft.X();
+ bDoMove = TRUE;
+ }
+ if ( rMove.Y() && aTopLeft.Y() >= rArea.Top() + rMove.Y() )
+ {
+ aMoveSize.Height() = rArea.Top() + rMove.Y() - SHRINK_DIST - aTopLeft.Y();
+ bDoMove = TRUE;
+ }
+ }
+ if ( bDoMove )
+ {
+ if ( bNegativePage )
+ {
+ if ( aTopLeft.X() + aMoveSize.Width() > 0 )
+ aMoveSize.Width() = -aTopLeft.X();
+ }
+ else
+ {
+ if ( aTopLeft.X() + aMoveSize.Width() < 0 )
+ aMoveSize.Width() = -aTopLeft.X();
+ }
+ if ( aTopLeft.Y() + aMoveSize.Height() < 0 )
+ aMoveSize.Height() = -aTopLeft.Y();
+
+ // get corresponding move size in millimeters:
+ Point aNewPos( aTopLeft.X() + aMoveSize.Width(), aTopLeft.Y() + aMoveSize.Height() );
+ lcl_TwipsToMM( aNewPos );
+ aMoveSize = Size( aNewPos.X() - aOldMMPos.X(), aNewPos.Y() - aOldMMPos.Y() ); // millimeters
+
+ AddCalcUndo( new SdrUndoMoveObj( *pObject, aMoveSize ) );
+ pObject->Move( aMoveSize );
+ }
+ else if ( rArea.IsInside( bNegativePage ? aObjRect.BottomLeft() : aObjRect.BottomRight() ) &&
+ !pObject->IsResizeProtect() )
+ {
+ // geschuetzte Groessen werden nicht veraendert
+ // (Positionen schon, weil sie ja an der Zelle "verankert" sind)
+ AddCalcUndo( new SdrUndoGeoObj( *pObject ) );
+ long nOldSizeX = aObjRect.Right() - aObjRect.Left() + 1;
+ long nOldSizeY = aObjRect.Bottom() - aObjRect.Top() + 1;
+ long nLogMoveX = rMove.X() * ( bNegativePage ? -1 : 1 ); // logical direction
+ pObject->Resize( aOldMMPos, Fraction( nOldSizeX+nLogMoveX, nOldSizeX ),
+ Fraction( nOldSizeY+rMove.Y(), nOldSizeY ) );
+ }
+ }
+ }
+ pObject = aIter.Next();
+ }
+}
+
+void ScDrawLayer::MoveArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1, SCCOL nCol2,SCROW nRow2,
+ SCsCOL nDx,SCsROW nDy, BOOL bInsDel )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::MoveArea without document" );
+ if ( !pDoc )
+ return;
+
+ if (!bAdjustEnabled)
+ return;
+
+ BOOL bNegativePage = pDoc->IsNegativePage( nTab );
+
+ Rectangle aRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
+ lcl_ReverseTwipsToMM( aRect );
+ //! use twips directly?
+
+ Point aMove;
+
+ if (nDx > 0)
+ for (SCsCOL s=0; s<nDx; s++)
+ aMove.X() += pDoc->GetColWidth(s+(SCsCOL)nCol1,nTab);
+ else
+ for (SCsCOL s=-1; s>=nDx; s--)
+ aMove.X() -= pDoc->GetColWidth(s+(SCsCOL)nCol1,nTab);
+ if (nDy > 0)
+ aMove.Y() += pDoc->FastGetRowHeight( nRow1, nRow1+nDy-1, nTab);
+ else
+ aMove.Y() -= pDoc->FastGetRowHeight( nRow1+nDy, nRow1-1, nTab);
+
+ if ( bNegativePage )
+ aMove.X() = -aMove.X();
+
+ Point aTopLeft = aRect.TopLeft(); // Anfang beim Verkleinern
+ if (bInsDel)
+ {
+ if ( aMove.X() != 0 && nDx < 0 ) // nDx counts cells, sign is independent of RTL
+ aTopLeft.X() += aMove.X();
+ if ( aMove.Y() < 0 )
+ aTopLeft.Y() += aMove.Y();
+ }
+
+ // drawing objects are now directly included in cut&paste
+ // -> only update references when inserting/deleting (or changing widths or heights)
+ if ( bInsDel )
+ MoveAreaTwips( nTab, aRect, aMove, aTopLeft );
+
+ //
+ // Detektiv-Pfeile: Zellpositionen anpassen
+ //
+
+ MoveCells( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy );
+}
+
+void ScDrawLayer::WidthChanged( SCTAB nTab, SCCOL nCol, long nDifTwips )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::WidthChanged without document" );
+ if ( !pDoc )
+ return;
+
+ if (!bAdjustEnabled)
+ return;
+
+ Rectangle aRect;
+ Point aTopLeft;
+
+ for (SCCOL i=0; i<nCol; i++)
+ aRect.Left() += pDoc->GetColWidth(i,nTab);
+ aTopLeft.X() = aRect.Left();
+ aRect.Left() += pDoc->GetColWidth(nCol,nTab);
+
+ aRect.Right() = MAXMM;
+ aRect.Top() = 0;
+ aRect.Bottom() = MAXMM;
+
+ //! aTopLeft ist falsch, wenn mehrere Spalten auf einmal ausgeblendet werden
+
+ BOOL bNegativePage = pDoc->IsNegativePage( nTab );
+ if ( bNegativePage )
+ {
+ MirrorRectRTL( aRect );
+ aTopLeft.X() = -aTopLeft.X();
+ nDifTwips = -nDifTwips;
+ }
+
+ MoveAreaTwips( nTab, aRect, Point( nDifTwips,0 ), aTopLeft );
+}
+
+void ScDrawLayer::HeightChanged( SCTAB nTab, SCROW nRow, long nDifTwips )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::HeightChanged without document" );
+ if ( !pDoc )
+ return;
+
+ if (!bAdjustEnabled)
+ return;
+
+ Rectangle aRect;
+ Point aTopLeft;
+
+ aRect.Top() += pDoc->FastGetRowHeight( 0, nRow-1, nTab);
+ aTopLeft.Y() = aRect.Top();
+ aRect.Top() += pDoc->FastGetRowHeight(nRow,nTab);
+
+ aRect.Bottom() = MAXMM;
+ aRect.Left() = 0;
+ aRect.Right() = MAXMM;
+
+ //! aTopLeft ist falsch, wenn mehrere Zeilen auf einmal ausgeblendet werden
+
+ BOOL bNegativePage = pDoc->IsNegativePage( nTab );
+ if ( bNegativePage )
+ {
+ MirrorRectRTL( aRect );
+ aTopLeft.X() = -aTopLeft.X();
+ }
+
+ MoveAreaTwips( nTab, aRect, Point( 0,nDifTwips ), aTopLeft );
+}
+
+BOOL ScDrawLayer::HasObjectsInRows( SCTAB nTab, SCROW nStartRow, SCROW nEndRow )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::HasObjectsInRows without document" );
+ if ( !pDoc )
+ return FALSE;
+
+ Rectangle aTestRect;
+
+ aTestRect.Top() += pDoc->FastGetRowHeight( 0, nStartRow-1, nTab);
+
+ if (nEndRow==MAXROW)
+ aTestRect.Bottom() = MAXMM;
+ else
+ {
+ aTestRect.Bottom() = aTestRect.Top();
+ aTestRect.Bottom() += pDoc->FastGetRowHeight( nStartRow, nEndRow, nTab);
+ TwipsToMM( aTestRect.Bottom() );
+ }
+
+ TwipsToMM( aTestRect.Top() );
+
+ aTestRect.Left() = 0;
+ aTestRect.Right() = MAXMM;
+
+ BOOL bNegativePage = pDoc->IsNegativePage( nTab );
+ if ( bNegativePage )
+ MirrorRectRTL( aTestRect );
+
+ SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page nicht gefunden");
+ if (!pPage)
+ return FALSE;
+
+ BOOL bFound = FALSE;
+
+ Rectangle aObjRect;
+ SdrObjListIter aIter( *pPage );
+ SdrObject* pObject = aIter.Next();
+ while ( pObject && !bFound )
+ {
+ aObjRect = pObject->GetSnapRect(); //! GetLogicRect ?
+ if (aTestRect.IsInside(aObjRect.TopLeft()) || aTestRect.IsInside(aObjRect.BottomLeft()))
+ bFound = TRUE;
+
+ pObject = aIter.Next();
+ }
+
+ return bFound;
+}
+
+#if 0
+void ScDrawLayer::DeleteObjects( SCTAB nTab )
+{
+ SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (!pPage)
+ return;
+
+ pPage->RecalcObjOrdNums();
+
+ long nDelCount = 0;
+ ULONG nObjCount = pPage->GetObjCount();
+ if (nObjCount)
+ {
+ SdrObject** ppObj = new SdrObject*[nObjCount];
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ // alle loeschen
+ ppObj[nDelCount++] = pObject;
+ pObject = aIter.Next();
+ }
+
+ long i;
+ if (bRecording)
+ for (i=1; i<=nDelCount; i++)
+ AddCalcUndo( new SdrUndoRemoveObj( *ppObj[nDelCount-i] ) );
+
+ for (i=1; i<=nDelCount; i++)
+ pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
+
+ delete[] ppObj;
+ }
+}
+#endif
+
+void ScDrawLayer::DeleteObjectsInArea( SCTAB nTab, SCCOL nCol1,SCROW nRow1,
+ SCCOL nCol2,SCROW nRow2 )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::DeleteObjectsInArea without document" );
+ if ( !pDoc )
+ return;
+
+ SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
+ DBG_ASSERT(pPage,"Page ?");
+ if (!pPage)
+ return;
+
+ pPage->RecalcObjOrdNums();
+
+ long nDelCount = 0;
+ ULONG nObjCount = pPage->GetObjCount();
+ if (nObjCount)
+ {
+ Rectangle aDelRect = pDoc->GetMMRect( nCol1, nRow1, nCol2, nRow2, nTab );
+
+ SdrObject** ppObj = new SdrObject*[nObjCount];
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ // do not delete note caption, they are always handled by the cell note
+ // TODO: detective objects are still deleted, is this desired?
+ if (!IsNoteCaption( pObject ))
+ {
+ Rectangle aObjRect = pObject->GetCurrentBoundRect();
+ if ( aDelRect.IsInside( aObjRect ) )
+ ppObj[nDelCount++] = pObject;
+ }
+
+ pObject = aIter.Next();
+ }
+
+ long i;
+ if (bRecording)
+ for (i=1; i<=nDelCount; i++)
+ AddCalcUndo( new SdrUndoRemoveObj( *ppObj[nDelCount-i] ) );
+
+ for (i=1; i<=nDelCount; i++)
+ pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
+
+ delete[] ppObj;
+ }
+}
+
+void ScDrawLayer::DeleteObjectsInSelection( const ScMarkData& rMark )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::DeleteObjectsInSelection without document" );
+ if ( !pDoc )
+ return;
+
+ if ( !rMark.IsMultiMarked() )
+ return;
+
+ ScRange aMarkRange;
+ rMark.GetMultiMarkArea( aMarkRange );
+
+ SCTAB nTabCount = pDoc->GetTableCount();
+ for (SCTAB nTab=0; nTab<=nTabCount; nTab++)
+ if ( rMark.GetTableSelect( nTab ) )
+ {
+ SdrPage* pPage = GetPage(static_cast<sal_uInt16>(nTab));
+ if (pPage)
+ {
+ pPage->RecalcObjOrdNums();
+ long nDelCount = 0;
+ ULONG nObjCount = pPage->GetObjCount();
+ if (nObjCount)
+ {
+ // Rechteck um die ganze Selektion
+ Rectangle aMarkBound = pDoc->GetMMRect(
+ aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
+ aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab );
+
+ SdrObject** ppObj = new SdrObject*[nObjCount];
+
+ SdrObjListIter aIter( *pPage, IM_FLAT );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ // do not delete note caption, they are always handled by the cell note
+ // TODO: detective objects are still deleted, is this desired?
+ if (!IsNoteCaption( pObject ))
+ {
+ Rectangle aObjRect = pObject->GetCurrentBoundRect();
+ if ( aMarkBound.IsInside( aObjRect ) )
+ {
+ ScRange aRange = pDoc->GetRange( nTab, aObjRect );
+ if (rMark.IsAllMarked(aRange))
+ ppObj[nDelCount++] = pObject;
+ }
+ }
+
+ pObject = aIter.Next();
+ }
+
+ // Objekte loeschen (rueckwaerts)
+
+ long i;
+ if (bRecording)
+ for (i=1; i<=nDelCount; i++)
+ AddCalcUndo( new SdrUndoRemoveObj( *ppObj[nDelCount-i] ) );
+
+ for (i=1; i<=nDelCount; i++)
+ pPage->RemoveObject( ppObj[nDelCount-i]->GetOrdNum() );
+
+ delete[] ppObj;
+ }
+ }
+ else
+ {
+ DBG_ERROR("pPage?");
+ }
+ }
+}
+
+void ScDrawLayer::CopyToClip( ScDocument* pClipDoc, SCTAB nTab, const Rectangle& rRange )
+{
+ // copy everything in the specified range into the same page (sheet) in the clipboard doc
+
+ SdrPage* pSrcPage = GetPage(static_cast<sal_uInt16>(nTab));
+ if (pSrcPage)
+ {
+ ScDrawLayer* pDestModel = NULL;
+ SdrPage* pDestPage = NULL;
+
+ SdrObjListIter aIter( *pSrcPage, IM_FLAT );
+ SdrObject* pOldObject = aIter.Next();
+ while (pOldObject)
+ {
+ Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
+ // do not copy internal objects (detective) and note captions
+ if ( rRange.IsInside( aObjRect ) && (pOldObject->GetLayer() != SC_LAYER_INTERN) && !IsNoteCaption( pOldObject ) )
+ {
+ if ( !pDestModel )
+ {
+ pDestModel = pClipDoc->GetDrawLayer(); // does the document already have a drawing layer?
+ if ( !pDestModel )
+ {
+ // allocate drawing layer in clipboard document only if there are objects to copy
+
+ pClipDoc->InitDrawLayer(); //! create contiguous pages
+ pDestModel = pClipDoc->GetDrawLayer();
+ }
+ if (pDestModel)
+ pDestPage = pDestModel->GetPage( static_cast<sal_uInt16>(nTab) );
+ }
+
+ DBG_ASSERT( pDestPage, "no page" );
+ if (pDestPage)
+ {
+ // #116235#
+ SdrObject* pNewObject = pOldObject->Clone();
+ //SdrObject* pNewObject = pOldObject->Clone( pDestPage, pDestModel );
+ pNewObject->SetModel(pDestModel);
+ pNewObject->SetPage(pDestPage);
+
+ pNewObject->NbcMove(Size(0,0));
+ pDestPage->InsertObject( pNewObject );
+
+ // no undo needed in clipboard document
+ // charts are not updated
+ }
+ }
+
+ pOldObject = aIter.Next();
+ }
+ }
+}
+
+BOOL lcl_IsAllInRange( const ScRangeList& rRanges, const ScRange& rClipRange )
+{
+ // check if every range of rRanges is completely in rClipRange
+
+ ULONG nCount = rRanges.Count();
+ for (ULONG i=0; i<nCount; i++)
+ {
+ ScRange aRange = *rRanges.GetObject(i);
+ if ( !rClipRange.In( aRange ) )
+ {
+ return FALSE; // at least one range is not valid
+ }
+ }
+
+ return TRUE; // everything is fine
+}
+
+BOOL lcl_MoveRanges( ScRangeList& rRanges, const ScRange& rSourceRange, const ScAddress& rDestPos )
+{
+ BOOL bChanged = FALSE;
+
+ ULONG nCount = rRanges.Count();
+ for (ULONG i=0; i<nCount; i++)
+ {
+ ScRange* pRange = rRanges.GetObject(i);
+ if ( rSourceRange.In( *pRange ) )
+ {
+ SCsCOL nDiffX = rDestPos.Col() - (SCsCOL)rSourceRange.aStart.Col();
+ SCsROW nDiffY = rDestPos.Row() - (SCsROW)rSourceRange.aStart.Row();
+ SCsTAB nDiffZ = rDestPos.Tab() - (SCsTAB)rSourceRange.aStart.Tab();
+ pRange->Move( nDiffX, nDiffY, nDiffZ );
+ bChanged = TRUE;
+ }
+ }
+
+ return bChanged;
+}
+
+void ScDrawLayer::CopyFromClip( ScDrawLayer* pClipModel, SCTAB nSourceTab, const Rectangle& rSourceRange,
+ const ScAddress& rDestPos, const Rectangle& rDestRange )
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::CopyFromClip without document" );
+ if ( !pDoc )
+ return;
+
+ if (!pClipModel)
+ return;
+
+ if (bDrawIsInUndo) //! can this happen?
+ {
+ DBG_ERROR("CopyFromClip, bDrawIsInUndo");
+ return;
+ }
+
+ BOOL bMirrorObj = ( rSourceRange.Left() < 0 && rSourceRange.Right() < 0 &&
+ rDestRange.Left() > 0 && rDestRange.Right() > 0 ) ||
+ ( rSourceRange.Left() > 0 && rSourceRange.Right() > 0 &&
+ rDestRange.Left() < 0 && rDestRange.Right() < 0 );
+ Rectangle aMirroredSource = rSourceRange;
+ if ( bMirrorObj )
+ MirrorRectRTL( aMirroredSource );
+
+ SCTAB nDestTab = rDestPos.Tab();
+
+ SdrPage* pSrcPage = pClipModel->GetPage(static_cast<sal_uInt16>(nSourceTab));
+ SdrPage* pDestPage = GetPage(static_cast<sal_uInt16>(nDestTab));
+ DBG_ASSERT( pSrcPage && pDestPage, "draw page missing" );
+ if ( !pSrcPage || !pDestPage )
+ return;
+
+ // first mirror, then move
+ Size aMove( rDestRange.Left() - aMirroredSource.Left(), rDestRange.Top() - aMirroredSource.Top() );
+
+ long nDestWidth = rDestRange.GetWidth();
+ long nDestHeight = rDestRange.GetHeight();
+ long nSourceWidth = rSourceRange.GetWidth();
+ long nSourceHeight = rSourceRange.GetHeight();
+
+ long nWidthDiff = nDestWidth - nSourceWidth;
+ long nHeightDiff = nDestHeight - nSourceHeight;
+
+ Fraction aHorFract(1,1);
+ Fraction aVerFract(1,1);
+ BOOL bResize = FALSE;
+ // sizes can differ by 1 from twips->1/100mm conversion for equal cell sizes,
+ // don't resize to empty size when pasting into hidden columns or rows
+ if ( Abs(nWidthDiff) > 1 && nDestWidth > 1 && nSourceWidth > 1 )
+ {
+ aHorFract = Fraction( nDestWidth, nSourceWidth );
+ bResize = TRUE;
+ }
+ if ( Abs(nHeightDiff) > 1 && nDestHeight > 1 && nSourceHeight > 1 )
+ {
+ aVerFract = Fraction( nDestHeight, nSourceHeight );
+ bResize = TRUE;
+ }
+ Point aRefPos = rDestRange.TopLeft(); // for resizing (after moving)
+
+ SdrObjListIter aIter( *pSrcPage, IM_FLAT );
+ SdrObject* pOldObject = aIter.Next();
+ while (pOldObject)
+ {
+ Rectangle aObjRect = pOldObject->GetCurrentBoundRect();
+ // do not copy internal objects (detective) and note captions
+ if ( rSourceRange.IsInside( aObjRect ) && (pOldObject->GetLayer() != SC_LAYER_INTERN) && !IsNoteCaption( pOldObject ) )
+ {
+ // #116235#
+ SdrObject* pNewObject = pOldObject->Clone();
+ //SdrObject* pNewObject = pOldObject->Clone( pDestPage, this );
+ pNewObject->SetModel(this);
+ pNewObject->SetPage(pDestPage);
+
+ if ( bMirrorObj )
+ MirrorRTL( pNewObject ); // first mirror, then move
+
+ pNewObject->NbcMove( aMove );
+ if ( bResize )
+ pNewObject->NbcResize( aRefPos, aHorFract, aVerFract );
+
+ pDestPage->InsertObject( pNewObject );
+ if (bRecording)
+ AddCalcUndo( new SdrUndoInsertObj( *pNewObject ) );
+
+ // handle chart data references (after InsertObject)
+
+ if ( pNewObject->GetObjIdentifier() == OBJ_OLE2 )
+ {
+ uno::Reference< embed::XEmbeddedObject > xIPObj = ((SdrOle2Obj*)pNewObject)->GetObjRef();
+ uno::Reference< embed::XClassifiedObject > xClassified( xIPObj, uno::UNO_QUERY );
+ SvGlobalName aObjectClassName;
+ if ( xClassified.is() )
+ {
+ try {
+ aObjectClassName = SvGlobalName( xClassified->getClassID() );
+ } catch( uno::Exception& )
+ {
+ // TODO: handle error?
+ }
+ }
+
+ if ( xIPObj.is() && SotExchange::IsChart( aObjectClassName ) )
+ {
+ String aNewName = ((SdrOle2Obj*)pNewObject)->GetPersistName();
+
+ //! need to set new DataProvider, or does Chart handle this itself?
+
+ ScRangeListRef xRanges( new ScRangeList );
+ BOOL bColHeaders = FALSE;
+ BOOL bRowHeaders = FALSE;
+ pDoc->GetOldChartParameters( aNewName, *xRanges, bColHeaders, bRowHeaders );
+
+ if ( xRanges->Count() > 0 )
+ {
+ ScDocument* pClipDoc = pClipModel->GetDocument();
+
+ // a clipboard document and its source share the same document item pool,
+ // so the pointers can be compared to see if this is copy&paste within
+ // the same document
+ BOOL bSameDoc = pDoc && pClipDoc && pDoc->GetPool() == pClipDoc->GetPool();
+
+ BOOL bDestClip = pDoc && pDoc->IsClipboard();
+
+ BOOL bInSourceRange = FALSE;
+ ScRange aClipRange;
+ if ( pClipDoc )
+ {
+ SCCOL nClipStartX;
+ SCROW nClipStartY;
+ SCCOL nClipEndX;
+ SCROW nClipEndY;
+ pClipDoc->GetClipStart( nClipStartX, nClipStartY );
+ pClipDoc->GetClipArea( nClipEndX, nClipEndY, TRUE );
+ nClipEndX = nClipEndX + nClipStartX;
+ nClipEndY += nClipStartY; // GetClipArea returns the difference
+
+ aClipRange = ScRange( nClipStartX, nClipStartY, nSourceTab,
+ nClipEndX, nClipEndY, nSourceTab );
+
+ bInSourceRange = lcl_IsAllInRange( *xRanges, aClipRange );
+ }
+
+ // always lose references when pasting into a clipboard document (transpose)
+ if ( ( bInSourceRange || bSameDoc ) && !bDestClip )
+ {
+ if ( bInSourceRange )
+ {
+ if ( rDestPos != aClipRange.aStart )
+ {
+ // update the data ranges to the new (copied) position
+ ScRangeListRef xNewRanges = new ScRangeList( *xRanges );
+ if ( lcl_MoveRanges( *xNewRanges, aClipRange, rDestPos ) )
+ {
+ pDoc->UpdateChartArea( aNewName, xNewRanges, bColHeaders, bRowHeaders, FALSE );
+ }
+ }
+ }
+ else
+ {
+ // leave the ranges unchanged
+ }
+ }
+ else
+ {
+ // pasting into a new document without the complete source data
+ // -> break connection to source data
+
+ // (see ScDocument::UpdateChartListenerCollection, PastingDrawFromOtherDoc)
+
+ //! need chart interface to switch to own data
+ }
+ }
+ }
+ }
+ }
+
+ pOldObject = aIter.Next();
+ }
+}
+
+void ScDrawLayer::MirrorRTL( SdrObject* pObj )
+{
+ UINT16 nIdent = pObj->GetObjIdentifier();
+
+ // don't mirror OLE or graphics, otherwise ask the object
+ // if it can be mirrored
+ BOOL bCanMirror = ( nIdent != OBJ_GRAF && nIdent != OBJ_OLE2 );
+ if (bCanMirror)
+ {
+ SdrObjTransformInfoRec aInfo;
+ pObj->TakeObjInfo( aInfo );
+ bCanMirror = aInfo.bMirror90Allowed;
+ }
+
+ if (bCanMirror)
+ {
+ Point aRef1( 0, 0 );
+ Point aRef2( 0, 1 );
+ if (bRecording)
+ AddCalcUndo( new SdrUndoGeoObj( *pObj ) );
+ pObj->Mirror( aRef1, aRef2 );
+ }
+ else
+ {
+ // Move instead of mirroring:
+ // New start position is negative of old end position
+ // -> move by sum of start and end position
+ Rectangle aObjRect = pObj->GetLogicRect();
+ Size aMoveSize( -(aObjRect.Left() + aObjRect.Right()), 0 );
+ if (bRecording)
+ AddCalcUndo( new SdrUndoMoveObj( *pObj, aMoveSize ) );
+ pObj->Move( aMoveSize );
+ }
+}
+
+// static
+void ScDrawLayer::MirrorRectRTL( Rectangle& rRect )
+{
+ // mirror and swap left/right
+ long nTemp = rRect.Left();
+ rRect.Left() = -rRect.Right();
+ rRect.Right() = -nTemp;
+}
+
+Rectangle ScDrawLayer::GetCellRect( ScDocument& rDoc, const ScAddress& rPos, bool bMergedCell )
+{
+ Rectangle aCellRect;
+ DBG_ASSERT( ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ), "ScDrawLayer::GetCellRect - invalid cell address" );
+ if( ValidColRowTab( rPos.Col(), rPos.Row(), rPos.Tab() ) )
+ {
+ // find top left position of passed cell address
+ Point aTopLeft;
+ for( SCCOL nCol = 0; nCol < rPos.Col(); ++nCol )
+ aTopLeft.X() += rDoc.GetColWidth( nCol, rPos.Tab() );
+ if( rPos.Row() > 0 )
+ aTopLeft.Y() += rDoc.FastGetRowHeight( 0, rPos.Row() - 1, rPos.Tab() );
+
+ // find bottom-right position of passed cell address
+ ScAddress aEndPos = rPos;
+ if( bMergedCell )
+ {
+ const ScMergeAttr* pMerge = static_cast< const ScMergeAttr* >( rDoc.GetAttr( rPos.Col(), rPos.Row(), rPos.Tab(), ATTR_MERGE ) );
+ if( pMerge->GetColMerge() > 1 )
+ aEndPos.IncCol( pMerge->GetColMerge() - 1 );
+ if( pMerge->GetRowMerge() > 1 )
+ aEndPos.IncRow( pMerge->GetRowMerge() - 1 );
+ }
+ Point aBotRight = aTopLeft;
+ for( SCCOL nCol = rPos.Col(); nCol <= aEndPos.Col(); ++nCol )
+ aBotRight.X() += rDoc.GetColWidth( nCol, rPos.Tab() );
+ aBotRight.Y() += rDoc.FastGetRowHeight( rPos.Row(), aEndPos.Row(), rPos.Tab() );
+
+ // twips -> 1/100 mm
+ aTopLeft.X() = static_cast< long >( aTopLeft.X() * HMM_PER_TWIPS );
+ aTopLeft.Y() = static_cast< long >( aTopLeft.Y() * HMM_PER_TWIPS );
+ aBotRight.X() = static_cast< long >( aBotRight.X() * HMM_PER_TWIPS );
+ aBotRight.Y() = static_cast< long >( aBotRight.Y() * HMM_PER_TWIPS );
+
+ aCellRect = Rectangle( aTopLeft, aBotRight );
+ if( rDoc.IsNegativePage( rPos.Tab() ) )
+ MirrorRectRTL( aCellRect );
+ }
+ return aCellRect;
+}
+
+// static
+String ScDrawLayer::GetVisibleName( SdrObject* pObj )
+{
+ String aName = pObj->GetName();
+ if ( pObj->GetObjIdentifier() == OBJ_OLE2 )
+ {
+ // #95575# For OLE, the user defined name (GetName) is used
+ // if it's not empty (accepting possibly duplicate names),
+ // otherwise the persist name is used so every object appears
+ // in the Navigator at all.
+
+ if ( !aName.Len() )
+ aName = static_cast<SdrOle2Obj*>(pObj)->GetPersistName();
+ }
+ return aName;
+}
+
+inline sal_Bool IsNamedObject( SdrObject* pObj, const String& rName )
+{
+ // TRUE if rName is the object's Name or PersistName
+ // (used to find a named object)
+
+ return ( pObj->GetName() == rName ||
+ ( pObj->GetObjIdentifier() == OBJ_OLE2 &&
+ static_cast<SdrOle2Obj*>(pObj)->GetPersistName() == rName ) );
+}
+
+SdrObject* ScDrawLayer::GetNamedObject( const String& rName, USHORT nId, SCTAB& rFoundTab ) const
+{
+ sal_uInt16 nTabCount = GetPageCount();
+ for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
+ {
+ const SdrPage* pPage = GetPage(nTab);
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( *pPage, IM_DEEPWITHGROUPS );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( nId == 0 || pObject->GetObjIdentifier() == nId )
+ if ( IsNamedObject( pObject, rName ) )
+ {
+ rFoundTab = static_cast<SCTAB>(nTab);
+ return pObject;
+ }
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+
+ return NULL;
+}
+
+String ScDrawLayer::GetNewGraphicName( long* pnCounter ) const
+{
+ String aBase = ScGlobal::GetRscString(STR_GRAPHICNAME);
+ aBase += ' ';
+
+ BOOL bThere = TRUE;
+ String aGraphicName;
+ SCTAB nDummy;
+ long nId = pnCounter ? *pnCounter : 0;
+ while (bThere)
+ {
+ ++nId;
+ aGraphicName = aBase;
+ aGraphicName += String::CreateFromInt32( nId );
+ bThere = ( GetNamedObject( aGraphicName, 0, nDummy ) != NULL );
+ }
+
+ if ( pnCounter )
+ *pnCounter = nId;
+
+ return aGraphicName;
+}
+
+void ScDrawLayer::EnsureGraphicNames()
+{
+ // make sure all graphic objects have names (after Excel import etc.)
+
+ sal_uInt16 nTabCount = GetPageCount();
+ for (sal_uInt16 nTab=0; nTab<nTabCount; nTab++)
+ {
+ SdrPage* pPage = GetPage(nTab);
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( *pPage, IM_DEEPWITHGROUPS );
+ SdrObject* pObject = aIter.Next();
+
+ /* #101799# The index passed to GetNewGraphicName() will be set to
+ the used index in each call. This prevents the repeated search
+ for all names from 1 to current index. */
+ long nCounter = 0;
+
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == OBJ_GRAF && pObject->GetName().Len() == 0 )
+ pObject->SetName( GetNewGraphicName( &nCounter ) );
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+}
+
+void ScDrawLayer::SetAnchor( SdrObject* pObj, ScAnchorType eType )
+{
+ // Ein an der Seite verankertes Objekt zeichnet sich durch eine Anker-Pos
+ // von (0,1) aus. Das ist ein shabby Trick, der aber funktioniert!
+ Point aAnchor( 0, eType == SCA_PAGE ? 1 : 0 );
+ pObj->SetAnchorPos( aAnchor );
+}
+
+ScAnchorType ScDrawLayer::GetAnchor( const SdrObject* pObj )
+{
+ Point aAnchor( pObj->GetAnchorPos() );
+ return ( aAnchor.Y() != 0 ) ? SCA_PAGE : SCA_CELL;
+}
+
+ScDrawObjData* ScDrawLayer::GetObjData( SdrObject* pObj, BOOL bCreate ) // static
+{
+ USHORT nCount = pObj ? pObj->GetUserDataCount() : 0;
+ for( USHORT i = 0; i < nCount; i++ )
+ {
+ SdrObjUserData* pData = pObj->GetUserData( i );
+ if( pData && pData->GetInventor() == SC_DRAWLAYER
+ && pData->GetId() == SC_UD_OBJDATA )
+ return (ScDrawObjData*) pData;
+ }
+ if( pObj && bCreate )
+ {
+ ScDrawObjData* pData = new ScDrawObjData;
+ pObj->InsertUserData( pData, 0 );
+ return pData;
+ }
+ return 0;
+}
+
+ScDrawObjData* ScDrawLayer::GetObjDataTab( SdrObject* pObj, SCTAB nTab ) // static
+{
+ ScDrawObjData* pData = GetObjData( pObj );
+ if ( pData )
+ {
+ if ( pData->maStart.IsValid() )
+ pData->maStart.SetTab( nTab );
+ if ( pData->maEnd.IsValid() )
+ pData->maEnd.SetTab( nTab );
+ }
+ return pData;
+}
+
+bool ScDrawLayer::IsNoteCaption( SdrObject* pObj )
+{
+ ScDrawObjData* pData = pObj ? GetObjData( pObj ) : 0;
+ return pData && pData->mbNote;
+}
+
+ScDrawObjData* ScDrawLayer::GetNoteCaptionData( SdrObject* pObj, SCTAB nTab )
+{
+ ScDrawObjData* pData = pObj ? GetObjDataTab( pObj, nTab ) : 0;
+ return (pData && pData->mbNote) ? pData : 0;
+}
+
+ScIMapInfo* ScDrawLayer::GetIMapInfo( SdrObject* pObj ) // static
+{
+ USHORT nCount = pObj->GetUserDataCount();
+ for( USHORT i = 0; i < nCount; i++ )
+ {
+ SdrObjUserData* pData = pObj->GetUserData( i );
+ if( pData && pData->GetInventor() == SC_DRAWLAYER
+ && pData->GetId() == SC_UD_IMAPDATA )
+ return (ScIMapInfo*) pData;
+ }
+ return NULL;
+}
+
+// static:
+IMapObject* ScDrawLayer::GetHitIMapObject( SdrObject* pObj,
+ const Point& rWinPoint, const Window& rCmpWnd )
+{
+ const MapMode aMap100( MAP_100TH_MM );
+ MapMode aWndMode = rCmpWnd.GetMapMode();
+ Point aRelPoint( rCmpWnd.LogicToLogic( rWinPoint, &aWndMode, &aMap100 ) );
+ Rectangle aLogRect = rCmpWnd.LogicToLogic( pObj->GetLogicRect(), &aWndMode, &aMap100 );
+ ScIMapInfo* pIMapInfo = GetIMapInfo( pObj );
+ IMapObject* pIMapObj = NULL;
+
+ if ( pIMapInfo )
+ {
+ Size aGraphSize;
+ ImageMap& rImageMap = (ImageMap&) pIMapInfo->GetImageMap();
+ Graphic aGraphic;
+ BOOL bObjSupported = FALSE;
+
+ if ( pObj->ISA( SdrGrafObj ) ) // einfaches Grafik-Objekt
+ {
+ const SdrGrafObj* pGrafObj = (const SdrGrafObj*) pObj;
+ const GeoStat& rGeo = pGrafObj->GetGeoStat();
+ const Graphic& rGraphic = pGrafObj->GetGraphic();
+
+ // Drehung rueckgaengig
+ if ( rGeo.nDrehWink )
+ RotatePoint( aRelPoint, aLogRect.TopLeft(), -rGeo.nSin, rGeo.nCos );
+
+ // Spiegelung rueckgaengig
+ if ( ( (const SdrGrafObjGeoData*) pGrafObj->GetGeoData() )->bMirrored )
+ aRelPoint.X() = aLogRect.Right() + aLogRect.Left() - aRelPoint.X();
+
+ // ggf. Unshear:
+ if ( rGeo.nShearWink )
+ ShearPoint( aRelPoint, aLogRect.TopLeft(), -rGeo.nTan );
+
+
+ if ( rGraphic.GetPrefMapMode().GetMapUnit() == MAP_PIXEL )
+ aGraphSize = rCmpWnd.PixelToLogic( rGraphic.GetPrefSize(),
+ aMap100 );
+ else
+ aGraphSize = OutputDevice::LogicToLogic( rGraphic.GetPrefSize(),
+ rGraphic.GetPrefMapMode(),
+ aMap100 );
+
+ bObjSupported = TRUE;
+ }
+ else if ( pObj->ISA( SdrOle2Obj ) ) // OLE-Objekt
+ {
+ // TODO/LEAN: working with visual area needs running state
+ aGraphSize = ((SdrOle2Obj*)pObj)->GetOrigObjSize();
+ bObjSupported = TRUE;
+ }
+
+ // hat alles geklappt, dann HitTest ausfuehren
+ if ( bObjSupported )
+ {
+ // relativen Mauspunkt berechnen
+ aRelPoint -= aLogRect.TopLeft();
+ pIMapObj = rImageMap.GetHitIMapObject( aGraphSize, aLogRect.GetSize(), aRelPoint );
+ }
+ }
+
+ return pIMapObj;
+}
+
+ScMacroInfo* ScDrawLayer::GetMacroInfo( SdrObject* pObj, BOOL bCreate ) // static
+{
+ USHORT nCount = pObj->GetUserDataCount();
+ for( USHORT i = 0; i < nCount; i++ )
+ {
+ SdrObjUserData* pData = pObj->GetUserData( i );
+ if( pData && pData->GetInventor() == SC_DRAWLAYER
+ && pData->GetId() == SC_UD_MACRODATA )
+ return (ScMacroInfo*) pData;
+ }
+ if ( bCreate )
+ {
+ ScMacroInfo* pData = new ScMacroInfo;
+ pObj->InsertUserData( pData, 0 );
+ return pData;
+ }
+ return 0;
+}
+
+void ScDrawLayer::SetGlobalDrawPersist(SfxObjectShell* pPersist) // static
+{
+ DBG_ASSERT(!pGlobalDrawPersist,"SetGlobalDrawPersist mehrfach");
+ pGlobalDrawPersist = pPersist;
+}
+
+void __EXPORT ScDrawLayer::SetChanged( sal_Bool bFlg /* = sal_True */ )
+{
+ if ( bFlg && pDoc )
+ pDoc->SetChartListenerCollectionNeedsUpdate( TRUE );
+ FmFormModel::SetChanged( bFlg );
+}
+
+SvStream* __EXPORT ScDrawLayer::GetDocumentStream(SdrDocumentStreamInfo& rStreamInfo) const
+{
+ DBG_ASSERT( pDoc, "ScDrawLayer::GetDocumentStream without document" );
+ if ( !pDoc )
+ return NULL;
+
+ uno::Reference< embed::XStorage > xStorage = pDoc->GetDocumentShell() ?
+ pDoc->GetDocumentShell()->GetStorage() :
+ NULL;
+ SvStream* pRet = NULL;
+
+ if( xStorage.is() )
+ {
+ if( rStreamInfo.maUserData.Len() &&
+ ( rStreamInfo.maUserData.GetToken( 0, ':' ) ==
+ String( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.Package" ) ) ) )
+ {
+ const String aPicturePath( rStreamInfo.maUserData.GetToken( 1, ':' ) );
+
+ // graphic from picture stream in picture storage in XML package
+ if( aPicturePath.GetTokenCount( '/' ) == 2 )
+ {
+ const String aPictureStreamName( aPicturePath.GetToken( 1, '/' ) );
+ const String aPictureStorageName( aPicturePath.GetToken( 0, '/' ) );
+
+ try {
+ if ( xStorage->isStorageElement( aPictureStorageName ) )
+ {
+ uno::Reference< embed::XStorage > xPictureStorage =
+ xStorage->openStorageElement( aPictureStorageName, embed::ElementModes::READ );
+
+ if( xPictureStorage.is() &&
+ xPictureStorage->isStreamElement( aPictureStreamName ) )
+ {
+ uno::Reference< io::XStream > xStream =
+ xPictureStorage->openStreamElement( aPictureStreamName, embed::ElementModes::READ );
+ if ( xStream.is() )
+ pRet = ::utl::UcbStreamHelper::CreateStream( xStream );
+ }
+ }
+ }
+ catch( uno::Exception& )
+ {
+ // TODO: error handling
+ }
+ }
+ }
+ // the following code seems to be related to binary format
+//REMOVE else
+//REMOVE {
+//REMOVE pRet = pStor->OpenStream( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM(STRING_SCSTREAM)),
+//REMOVE STREAM_READ | STREAM_WRITE | STREAM_TRUNC );
+//REMOVE
+//REMOVE if( pRet )
+//REMOVE {
+//REMOVE pRet->SetVersion( pStor->GetVersion() );
+//REMOVE pRet->SetKey( pStor->GetKey() );
+//REMOVE }
+//REMOVE }
+
+ rStreamInfo.mbDeleteAfterUse = ( pRet != NULL );
+ }
+
+ return pRet;
+}
+
+//REMOVE void ScDrawLayer::ReleasePictureStorage()
+//REMOVE {
+//REMOVE xPictureStorage.Clear();
+//REMOVE }
+
+SdrLayerID __EXPORT ScDrawLayer::GetControlExportLayerId( const SdrObject & ) const
+{
+ // Layer fuer Export von Form-Controls in Versionen vor 5.0 - immer SC_LAYER_FRONT
+ return SC_LAYER_FRONT;
+}
+
+::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > ScDrawLayer::createUnoModel()
+{
+ ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > xRet;
+ if( pDoc && pDoc->GetDocumentShell() )
+ xRet = pDoc->GetDocumentShell()->GetModel();
+
+ return xRet;
+}
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
new file mode 100644
index 000000000000..c8eba91d2cc1
--- /dev/null
+++ b/sc/source/core/data/fillinfo.cxx
@@ -0,0 +1,1064 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: fillinfo.cxx,v $
+ * $Revision: 1.15 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/boxitem.hxx>
+#include <svx/bolnitem.hxx>
+#include <svx/editdata.hxx> // can be removed if table has a bLayoutRTL flag
+#include <svx/shaditem.hxx>
+
+#include "fillinfo.hxx"
+#include "document.hxx"
+#include "cell.hxx"
+#include "table.hxx"
+#include "attrib.hxx"
+#include "attarray.hxx"
+#include "markarr.hxx"
+#include "markdata.hxx"
+#include "patattr.hxx"
+#include "poolhelp.hxx"
+#include "docpool.hxx"
+#include "conditio.hxx"
+#include "stlpool.hxx"
+
+
+// -----------------------------------------------------------------------
+
+const USHORT ROWINFO_MAX = 1024;
+
+
+enum FillInfoLinePos
+ {
+ FILP_TOP,
+ FILP_BOTTOM,
+ FILP_LEFT,
+ FILP_RIGHT
+ };
+
+
+inline const SvxBorderLine* GetNullOrLine( const SvxBoxItem* pBox, FillInfoLinePos eWhich )
+{
+ if (pBox)
+ {
+ if (eWhich==FILP_TOP)
+ return pBox->GetTop();
+ else if (eWhich==FILP_BOTTOM)
+ return pBox->GetBottom();
+ else if (eWhich==FILP_LEFT)
+ return pBox->GetLeft();
+ else
+ return pBox->GetRight();
+ }
+ else
+ return NULL;
+}
+
+// aehnlich wie in output.cxx
+
+void lcl_GetMergeRange( SCsCOL nX, SCsROW nY, SCSIZE nArrY,
+ ScDocument* pDoc, RowInfo* pRowInfo,
+ SCCOL nX1, SCROW nY1, SCCOL /* nX2 */, SCROW /* nY2 */, SCTAB nTab,
+ SCsCOL& rStartX, SCsROW& rStartY, SCsCOL& rEndX, SCsROW& rEndY )
+{
+ CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nX+1];
+
+ rStartX = nX;
+ rStartY = nY;
+ BOOL bHOver = pInfo->bHOverlapped;
+ BOOL bVOver = pInfo->bVOverlapped;
+
+ while (bHOver) // nY konstant
+ {
+ --rStartX;
+ if (rStartX >= (SCsCOL) nX1 && (pDoc->GetColFlags(rStartX,nTab) & CR_HIDDEN) == 0)
+ {
+ bHOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bHOverlapped;
+ bVOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bVOverlapped;
+ }
+ else
+ {
+ USHORT nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr(
+ rStartX, rStartY, nTab, ATTR_MERGE_FLAG ))->GetValue();
+ bHOver = ((nOverlap & SC_MF_HOR) != 0);
+ bVOver = ((nOverlap & SC_MF_VER) != 0);
+ }
+ }
+
+ while (bVOver)
+ {
+ --rStartY;
+
+ if (nArrY>0)
+ --nArrY; // lokale Kopie !
+
+ if (rStartX >= (SCsCOL) nX1 && rStartY >= (SCsROW) nY1 &&
+ (pDoc->GetColFlags(rStartX,nTab) & CR_HIDDEN) == 0 &&
+ (pDoc->GetRowFlags(rStartY,nTab) & CR_HIDDEN) == 0 &&
+ (SCsROW) pRowInfo[nArrY].nRowNo == rStartY)
+ {
+ bHOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bHOverlapped;
+ bVOver = pRowInfo[nArrY].pCellInfo[rStartX+1].bVOverlapped;
+ }
+ else
+ {
+ USHORT nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr(
+ rStartX, rStartY, nTab, ATTR_MERGE_FLAG ))->GetValue();
+ bHOver = ((nOverlap & SC_MF_HOR) != 0);
+ bVOver = ((nOverlap & SC_MF_VER) != 0);
+ }
+ }
+
+ const ScMergeAttr* pMerge;
+ if (rStartX >= (SCsCOL) nX1 && rStartY >= (SCsROW) nY1 &&
+ (pDoc->GetColFlags(rStartX,nTab) & CR_HIDDEN) == 0 &&
+ (pDoc->GetRowFlags(rStartY,nTab) & CR_HIDDEN) == 0 &&
+ (SCsROW) pRowInfo[nArrY].nRowNo == rStartY)
+ {
+ pMerge = (const ScMergeAttr*) &pRowInfo[nArrY].pCellInfo[rStartX+1].pPatternAttr->
+ GetItem(ATTR_MERGE);
+ }
+ else
+ pMerge = (const ScMergeAttr*) pDoc->GetAttr(rStartX,rStartY,nTab,ATTR_MERGE);
+
+ rEndX = rStartX + pMerge->GetColMerge() - 1;
+ rEndY = rStartY + pMerge->GetRowMerge() - 1;
+}
+
+inline BOOL ScDocument::RowHidden( SCROW nRow, SCTAB nTab )
+{
+ return ( pTab[nTab]->pRowFlags->GetValue(nRow) & CR_HIDDEN ) != 0;
+}
+
+
+#define CELLINFO(x,y) pRowInfo[nArrY+y].pCellInfo[nArrX+x]
+
+void ScDocument::FillInfo( ScTableInfo& rTabInfo, SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ SCTAB nTab, double nScaleX, double nScaleY,
+ BOOL bPageMode, BOOL bFormulaMode, const ScMarkData* pMarkData )
+{
+ DBG_ASSERT( pTab[nTab], "Tabelle existiert nicht" );
+
+ BOOL bLayoutRTL = IsLayoutRTL( nTab );
+
+ ScDocumentPool* pPool = xPoolHelper->GetDocPool();
+ ScStyleSheetPool* pStlPool = xPoolHelper->GetStylePool();
+
+ RowInfo* pRowInfo = rTabInfo.mpRowInfo;
+
+ const SvxBrushItem* pDefBackground =
+ (const SvxBrushItem*) &pPool->GetDefaultItem( ATTR_BACKGROUND );
+ const ScMergeAttr* pDefMerge =
+ (const ScMergeAttr*) &pPool->GetDefaultItem( ATTR_MERGE );
+ const SvxShadowItem* pDefShadow =
+ (const SvxShadowItem*) &pPool->GetDefaultItem( ATTR_SHADOW );
+
+ SCROW nThisRow;
+ SCCOL nX;
+ SCROW nY;
+ SCsROW nSignedY;
+ SCCOL nArrX;
+ SCSIZE nArrY;
+ SCSIZE nArrCount;
+ BOOL bAnyMerged = FALSE;
+ BOOL bAnyShadow = FALSE;
+ BOOL bAnyCondition = FALSE;
+
+ BOOL bTabProtect = IsTabProtected(nTab);
+
+ // fuer Blockmarken von zusammengefassten Zellen mit
+ // versteckter erster Zeile / Spalte
+ BOOL bPaintMarks = FALSE;
+ BOOL bSkipMarks = FALSE;
+ SCCOL nBlockStartX = 0, nBlockEndX = 0;
+ SCROW nBlockEndY = 0, nBlockStartY = 0;
+ if (pMarkData && pMarkData->IsMarked())
+ {
+ ScRange aTmpRange;
+ pMarkData->GetMarkArea(aTmpRange);
+ if ( nTab >= aTmpRange.aStart.Tab() && nTab <= aTmpRange.aEnd.Tab() )
+ {
+ nBlockStartX = aTmpRange.aStart.Col();
+ nBlockStartY = aTmpRange.aStart.Row();
+ nBlockEndX = aTmpRange.aEnd.Col();
+ nBlockEndY = aTmpRange.aEnd.Row();
+ ExtendHidden( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY, nTab ); //? noetig ?
+ if (pMarkData->IsMarkNegative())
+ bSkipMarks = TRUE;
+ else
+ bPaintMarks = TRUE;
+ }
+ }
+
+ // zuerst nur die Eintraege fuer die ganze Spalte
+
+ nArrY=0;
+ SCROW nYExtra = nY2+1;
+ for (nSignedY=((SCsROW)nY1)-1; nSignedY<=(SCsROW)nYExtra; nSignedY++)
+ {
+ if (nSignedY >= 0)
+ nY = (SCROW) nSignedY;
+ else
+ nY = MAXROW+1; // ungueltig
+
+ USHORT nDocHeight;
+ if (ValidRow(nY))
+ nDocHeight = GetRowHeight( nY, nTab );
+ else
+ nDocHeight = ScGlobal::nStdRowHeight;
+
+ if ( nArrY==0 || nDocHeight || nY > MAXROW )
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ pThisRowInfo->pCellInfo = NULL; // wird unten belegt
+
+ USHORT nHeight = (USHORT) ( nDocHeight * nScaleY );
+ if (!nHeight)
+ nHeight = 1;
+
+ pThisRowInfo->nRowNo = nY; //! Fall < 0 ?
+ pThisRowInfo->nHeight = nHeight;
+ pThisRowInfo->bEmptyBack = TRUE;
+ pThisRowInfo->bEmptyText = TRUE;
+ pThisRowInfo->bChanged = TRUE;
+ pThisRowInfo->bAutoFilter = FALSE;
+ pThisRowInfo->bPushButton = FALSE;
+ pThisRowInfo->nRotMaxCol = SC_ROTMAX_NONE;
+
+ ++nArrY;
+ if (nArrY >= ROWINFO_MAX)
+ {
+ DBG_ERROR("Zu grosser Bereich bei FillInfo" );
+ nYExtra = nSignedY; // Ende
+ nY2 = nYExtra - 1; // Bereich anpassen
+ }
+ }
+ else
+ if (nSignedY==(SCsROW) nYExtra) // zusaetzliche Zeile verdeckt ?
+ ++nYExtra;
+ }
+ nArrCount = nArrY; // incl. Dummys
+
+ // rotierter Text...
+
+ // Attribut im Dokument ueberhaupt verwendet?
+ BOOL bAnyItem = FALSE;
+ USHORT nRotCount = pPool->GetItemCount( ATTR_ROTATE_VALUE );
+ for (USHORT nItem=0; nItem<nRotCount; nItem++)
+ if (pPool->GetItem( ATTR_ROTATE_VALUE, nItem ))
+ {
+ bAnyItem = TRUE;
+ break;
+ }
+
+ SCCOL nRotMax = nX2;
+ if ( bAnyItem && HasAttrib( 0,nY1,nTab, MAXCOL,nY2+1,nTab,
+ HASATTR_ROTATE | HASATTR_CONDITIONAL ) )
+ {
+ //! Conditionals auch bei HASATTR_ROTATE abfragen ????
+
+ DBG_ASSERT( nArrCount>2, "nArrCount zu klein" );
+// FindMaxRotCol( nTab, &pRowInfo[1], nArrCount-2, nX1, nX2 );
+ FindMaxRotCol( nTab, &pRowInfo[1], nArrCount-1, nX1, nX2 );
+ // FindMaxRotCol setzt nRotMaxCol
+
+ for (nArrY=0; nArrY<nArrCount; nArrY++)
+ if (pRowInfo[nArrY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nArrY].nRotMaxCol > nRotMax)
+ nRotMax = pRowInfo[nArrY].nRotMaxCol;
+ }
+
+ // Zell-Infos erst nach dem Test auf gedrehte allozieren
+ // bis nRotMax wegen nRotateDir Flag
+
+ for (nArrY=0; nArrY<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ nY = pThisRowInfo->nRowNo;
+ pThisRowInfo->pCellInfo = new CellInfo[ nRotMax+1+2 ]; // vom Aufrufer zu loeschen !
+
+ for (nArrX=0; nArrX<=nRotMax+2; nArrX++) // Zell-Infos vorbelegen
+ {
+ if (nArrX>0)
+ nX = nArrX-1;
+ else
+ nX = MAXCOL+1; // ungueltig
+
+ CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX];
+ pInfo->bEmptyCellText = TRUE;
+ pInfo->pCell = NULL;
+ if (bPaintMarks)
+ pInfo->bMarked = ( nX >= nBlockStartX && nX <= nBlockEndX
+ && nY >= nBlockStartY && nY <= nBlockEndY );
+ else
+ pInfo->bMarked = FALSE;
+ pInfo->nWidth = 0;
+
+ pInfo->nClipMark = SC_CLIPMARK_NONE;
+ pInfo->bMerged = FALSE;
+ pInfo->bHOverlapped = FALSE;
+ pInfo->bVOverlapped = FALSE;
+ pInfo->bAutoFilter = FALSE;
+ pInfo->bPushButton = FALSE;
+ pInfo->nRotateDir = SC_ROTDIR_NONE;
+
+ pInfo->bPrinted = FALSE; // view-intern
+ pInfo->bHideGrid = FALSE; // view-intern
+ pInfo->bEditEngine = FALSE; // view-intern
+
+ pInfo->pBackground = NULL; //! weglassen?
+ pInfo->pPatternAttr = NULL;
+ pInfo->pConditionSet= NULL;
+
+ pInfo->pLinesAttr = NULL;
+ pInfo->mpTLBRLine = NULL;
+ pInfo->mpBLTRLine = NULL;
+
+ pInfo->pShadowAttr = pDefShadow;
+ pInfo->pHShadowOrigin = NULL;
+ pInfo->pVShadowOrigin = NULL;
+ }
+ }
+
+ for (nArrX=nX2+3; nArrX<=nRotMax+2; nArrX++) // restliche Breiten eintragen
+ {
+ nX = nArrX-1;
+ if ( ValidCol(nX) )
+ {
+ if ( (GetColFlags(nX,nTab) & CR_HIDDEN) == 0 ) // Spalte nicht versteckt
+ {
+ USHORT nThisWidth = (USHORT) (GetColWidth( nX, nTab ) * nScaleX);
+ if (!nThisWidth)
+ nThisWidth = 1;
+
+ pRowInfo[0].pCellInfo[nArrX].nWidth = nThisWidth;
+ }
+ }
+ }
+
+ for (nArrX=0; nArrX<=nX2+2; nArrX++) // links & rechts + 1
+ {
+ nX = (nArrX>0) ? nArrX-1 : MAXCOL+1; // negativ -> ungueltig
+
+ if ( ValidCol(nX) )
+ {
+ // #i58049#, #i57939# Hidden columns must be skipped here, or their attributes
+ // will disturb the output
+
+ if ( (GetColFlags(nX,nTab) & CR_HIDDEN) == 0 ) // column not hidden
+ {
+ USHORT nThisWidth = (USHORT) (GetColWidth( nX, nTab ) * nScaleX);
+ if (!nThisWidth)
+ nThisWidth = 1;
+
+ pRowInfo[0].pCellInfo[nArrX].nWidth = nThisWidth; //! dies sollte reichen
+
+ ScColumn* pThisCol = &pTab[nTab]->aCol[nX]; // Spalten-Daten
+
+ nArrY = 1;
+ SCSIZE nUIndex;
+ (void) pThisCol->Search( nY1, nUIndex );
+ while ( nUIndex < pThisCol->nCount &&
+ (nThisRow=pThisCol->pItems[nUIndex].nRow) <= nY2 )
+ {
+ if ( !RowHidden( nThisRow,nTab ) )
+ {
+ while ( pRowInfo[nArrY].nRowNo < nThisRow )
+ ++nArrY;
+ DBG_ASSERT( pRowInfo[nArrY].nRowNo == nThisRow, "Zeile nicht gefunden in FillInfo" );
+
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX];
+ pInfo->pCell = pThisCol->pItems[nUIndex].pCell;
+ if (pInfo->pCell->GetCellType() != CELLTYPE_NOTE)
+ {
+ pThisRowInfo->bEmptyText = FALSE; // Zeile nicht leer
+ pInfo->bEmptyCellText = FALSE; // Zelle nicht leer
+ }
+ ++nArrY;
+ }
+ ++nUIndex;
+ }
+
+ if (nX+1 >= nX1) // Attribute/Blockmarken ab nX1-1
+ {
+ ScAttrArray* pThisAttrArr = pThisCol->pAttrArray; // Attribute
+
+ nArrY = 0;
+ const ScPatternAttr* pPattern;
+ SCROW nCurRow=nY1; // einzelne Zeile
+ if (nCurRow>0)
+ --nCurRow; // oben 1 mehr
+ else
+ nArrY = 1;
+ nThisRow=nCurRow; // Ende des Bereichs
+ SCSIZE nIndex;
+ (void) pThisAttrArr->Search( nCurRow, nIndex );
+
+
+ do
+ {
+ nThisRow=pThisAttrArr->pData[nIndex].nRow; // Ende des Bereichs
+ pPattern=pThisAttrArr->pData[nIndex].pPattern;
+
+ const SvxBrushItem* pBackground = (const SvxBrushItem*)
+ &pPattern->GetItem(ATTR_BACKGROUND);
+ const SvxBoxItem* pLinesAttr = (const SvxBoxItem*)
+ &pPattern->GetItem(ATTR_BORDER);
+
+ const SvxLineItem* pTLBRLine = static_cast< const SvxLineItem* >(
+ &pPattern->GetItem( ATTR_BORDER_TLBR ) );
+ const SvxLineItem* pBLTRLine = static_cast< const SvxLineItem* >(
+ &pPattern->GetItem( ATTR_BORDER_BLTR ) );
+
+ const SvxShadowItem* pShadowAttr = (const SvxShadowItem*)
+ &pPattern->GetItem(ATTR_SHADOW);
+ if (pShadowAttr != pDefShadow)
+ bAnyShadow = TRUE;
+
+ const ScMergeAttr* pMergeAttr = (const ScMergeAttr*)
+ &pPattern->GetItem(ATTR_MERGE);
+ BOOL bMerged = ( pMergeAttr != pDefMerge && *pMergeAttr != *pDefMerge );
+ USHORT nOverlap = ((const ScMergeFlagAttr*) &pPattern->GetItemSet().
+ Get(ATTR_MERGE_FLAG))->GetValue();
+ BOOL bHOverlapped = ((nOverlap & SC_MF_HOR) != 0);
+ BOOL bVOverlapped = ((nOverlap & SC_MF_VER) != 0);
+ BOOL bAutoFilter = ((nOverlap & SC_MF_AUTO) != 0);
+ BOOL bPushButton = ((nOverlap & SC_MF_BUTTON) != 0);
+ BOOL bScenario = ((nOverlap & SC_MF_SCENARIO) != 0);
+ if (bMerged||bHOverlapped||bVOverlapped)
+ bAnyMerged = TRUE; // intern
+
+ BOOL bHidden, bHideFormula;
+ if (bTabProtect)
+ {
+ const ScProtectionAttr& rProtAttr = (const ScProtectionAttr&)
+ pPattern->GetItem(ATTR_PROTECTION);
+ bHidden = rProtAttr.GetHideCell();
+ bHideFormula = rProtAttr.GetHideFormula();
+ }
+ else
+ bHidden = bHideFormula = FALSE;
+
+ ULONG nConditional = ((const SfxUInt32Item&)pPattern->
+ GetItem(ATTR_CONDITIONAL)).GetValue();
+ const ScConditionalFormat* pCondForm = NULL;
+ if ( nConditional && pCondFormList )
+ pCondForm = pCondFormList->GetFormat( nConditional );
+
+ do
+ {
+ if ( nArrY==0 || !RowHidden( nCurRow,nTab ) )
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ if (pBackground != pDefBackground) // Spalten-HG == Standard ?
+ pThisRowInfo->bEmptyBack = FALSE;
+ if (bAutoFilter)
+ pThisRowInfo->bAutoFilter = TRUE;
+ if (bPushButton)
+ pThisRowInfo->bPushButton = TRUE;
+
+ CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX];
+ pInfo->pBackground = pBackground;
+ pInfo->pPatternAttr = pPattern;
+ pInfo->bMerged = bMerged;
+ pInfo->bHOverlapped = bHOverlapped;
+ pInfo->bVOverlapped = bVOverlapped;
+ pInfo->bAutoFilter = bAutoFilter;
+ pInfo->bPushButton = bPushButton;
+ pInfo->pLinesAttr = pLinesAttr;
+ pInfo->mpTLBRLine = pTLBRLine;
+ pInfo->mpBLTRLine = pBLTRLine;
+ pInfo->pShadowAttr = pShadowAttr;
+ // nWidth wird nicht mehr einzeln gesetzt
+
+ BOOL bEmbed = FALSE; //bIsEmbedded &&
+ nTab >= aEmbedRange.aStart.Tab() &&
+ nTab <= aEmbedRange.aEnd.Tab() &&
+ nX >= aEmbedRange.aStart.Col() &&
+ nX <= aEmbedRange.aEnd.Col() &&
+ nCurRow >= aEmbedRange.aStart.Row() &&
+ nCurRow <= aEmbedRange.aEnd.Row();
+
+ if (bPushButton || bScenario)
+ {
+ pInfo->pBackground = ScGlobal::GetButtonBrushItem();
+ pThisRowInfo->bEmptyBack = FALSE;
+ }
+ else if (bEmbed)
+ {
+ pInfo->pBackground = ScGlobal::GetEmbeddedBrushItem();
+ pThisRowInfo->bEmptyBack = FALSE;
+ }
+
+ if (bHidden || ( bFormulaMode && bHideFormula && pInfo->pCell
+ && pInfo->pCell->GetCellType()
+ == CELLTYPE_FORMULA ))
+ pInfo->bEmptyCellText = TRUE;
+
+ if ( pCondForm )
+ {
+ String aStyle = pCondForm->GetCellStyle( pInfo->pCell,
+ ScAddress( nX, nCurRow, nTab ) );
+ if (aStyle.Len())
+ {
+ SfxStyleSheetBase* pStyleSheet =
+ pStlPool->Find( aStyle, SFX_STYLE_FAMILY_PARA );
+ if ( pStyleSheet )
+ {
+ //! Style-Sets cachen !!!
+ pInfo->pConditionSet = &pStyleSheet->GetItemSet();
+ bAnyCondition = TRUE;
+ }
+ // if style is not there, treat like no condition
+ }
+ }
+
+ ++nArrY;
+ }
+ ++nCurRow;
+ }
+ while (nCurRow <= nThisRow && nCurRow <= nYExtra);
+ ++nIndex;
+ }
+ while ( nIndex < pThisAttrArr->nCount && nThisRow < nYExtra );
+
+
+ if (pMarkData && pMarkData->IsMultiMarked())
+ {
+ // Blockmarken
+ const ScMarkArray* pThisMarkArr = pMarkData->GetArray()+nX;
+ BOOL bThisMarked;
+ nArrY = 1;
+ nCurRow = nY1; // einzelne Zeile
+ nThisRow = nY1; // Ende des Bereichs
+
+ if ( pThisMarkArr->Search( nY1, nIndex ) )
+ {
+ do
+ {
+ nThisRow=pThisMarkArr->pData[nIndex].nRow; // Ende des Bereichs
+ bThisMarked=pThisMarkArr->pData[nIndex].bMarked;
+
+ do
+ {
+ if ( !RowHidden( nCurRow,nTab ) )
+ {
+ if ( bThisMarked )
+ {
+ BOOL bSkip = bSkipMarks &&
+ nX >= nBlockStartX &&
+ nX <= nBlockEndX &&
+ nCurRow >= nBlockStartY &&
+ nCurRow <= nBlockEndY;
+ if (!bSkip)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX];
+ pInfo->bMarked = TRUE;
+ }
+ }
+ ++nArrY;
+ }
+ ++nCurRow;
+ }
+ while (nCurRow <= nThisRow && nCurRow <= nY2);
+ ++nIndex;
+ }
+ while ( nIndex < pThisMarkArr->nCount && nThisRow < nY2 );
+ }
+ }
+ }
+ else // vordere Spalten
+ {
+ for (nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX];
+
+ pInfo->nWidth = nThisWidth; //! oder nur 0 abfragen ??
+ }
+ }
+ }
+ }
+ else
+ pRowInfo[0].pCellInfo[nArrX].nWidth = STD_COL_WIDTH;
+ // STD_COL_WIDTH ganz links und rechts wird fuer DrawExtraShadow gebraucht
+ }
+
+ //-------------------------------------------------------------------------
+ // bedingte Formatierung auswerten
+
+ if (bAnyCondition)
+ {
+ for (nArrY=0; nArrY<nArrCount; nArrY++)
+ {
+ for (nArrX=nX1; nArrX<=nX2+2; nArrX++) // links und rechts einer mehr
+ {
+ CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nArrX];
+ const SfxItemSet* pCondSet = pInfo->pConditionSet;
+ if (pCondSet)
+ {
+ const SfxPoolItem* pItem;
+
+ // Hintergrund
+ if ( pCondSet->GetItemState( ATTR_BACKGROUND, TRUE, &pItem ) == SFX_ITEM_SET )
+ {
+ pInfo->pBackground = (const SvxBrushItem*) pItem;
+ pRowInfo[nArrY].bEmptyBack = FALSE;
+ }
+
+ // Umrandung
+ if ( pCondSet->GetItemState( ATTR_BORDER, TRUE, &pItem ) == SFX_ITEM_SET )
+ pInfo->pLinesAttr = (const SvxBoxItem*) pItem;
+
+ if ( pCondSet->GetItemState( ATTR_BORDER_TLBR, TRUE, &pItem ) == SFX_ITEM_SET )
+ pInfo->mpTLBRLine = static_cast< const SvxLineItem* >( pItem );
+ if ( pCondSet->GetItemState( ATTR_BORDER_BLTR, TRUE, &pItem ) == SFX_ITEM_SET )
+ pInfo->mpBLTRLine = static_cast< const SvxLineItem* >( pItem );
+
+ // Schatten
+ if ( pCondSet->GetItemState( ATTR_SHADOW, TRUE, &pItem ) == SFX_ITEM_SET )
+ {
+ pInfo->pShadowAttr = (const SvxShadowItem*) pItem;
+ bAnyShadow = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ // bedingte Formatierung Ende
+ //-------------------------------------------------------------------------
+
+ //
+ // Daten von zusammengefassten Zellen anpassen
+ //
+
+ if (bAnyMerged)
+ {
+ for (nArrY=0; nArrY<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ nSignedY = nArrY ? pThisRowInfo->nRowNo : ((SCsROW)nY1)-1;
+
+ for (nArrX=nX1; nArrX<=nX2+2; nArrX++) // links und rechts einer mehr
+ {
+ SCsCOL nSignedX = ((SCsCOL) nArrX) - 1;
+ CellInfo* pInfo = &pThisRowInfo->pCellInfo[nArrX];
+
+ if (pInfo->bMerged || pInfo->bHOverlapped || pInfo->bVOverlapped)
+ {
+ SCsCOL nStartX;
+ SCsROW nStartY;
+ SCsCOL nEndX;
+ SCsROW nEndY;
+ lcl_GetMergeRange( nSignedX,nSignedY, nArrY, this,pRowInfo, nX1,nY1,nX2,nY2,nTab,
+ nStartX,nStartY, nEndX,nEndY );
+ const ScPatternAttr* pStartPattern = GetPattern( nStartX,nStartY,nTab );
+ const SfxItemSet* pStartCond = GetCondResult( nStartX,nStartY,nTab );
+ const SfxPoolItem* pItem;
+
+ // Hintergrund kopieren (oder in output.cxx)
+
+ if ( !pStartCond || pStartCond->
+ GetItemState(ATTR_BACKGROUND,TRUE,&pItem) != SFX_ITEM_SET )
+ pItem = &pStartPattern->GetItem(ATTR_BACKGROUND);
+ pInfo->pBackground = (const SvxBrushItem*) pItem;
+ pRowInfo[nArrY].bEmptyBack = FALSE;
+
+ // Schatten
+
+ if ( !pStartCond || pStartCond->
+ GetItemState(ATTR_SHADOW,TRUE,&pItem) != SFX_ITEM_SET )
+ pItem = &pStartPattern->GetItem(ATTR_SHADOW);
+ pInfo->pShadowAttr = (const SvxShadowItem*) pItem;
+ if (pInfo->pShadowAttr != pDefShadow)
+ bAnyShadow = TRUE;
+
+ // Blockmarken - wieder mit Original-Merge-Werten
+
+ BOOL bCellMarked = FALSE;
+ if (bPaintMarks)
+ bCellMarked = ( nStartX >= (SCsCOL) nBlockStartX
+ && nStartX <= (SCsCOL) nBlockEndX
+ && nStartY >= (SCsROW) nBlockStartY
+ && nStartY <= (SCsROW) nBlockEndY );
+ if (pMarkData && pMarkData->IsMultiMarked() && !bCellMarked)
+ {
+ const ScMarkArray* pThisMarkArr = pMarkData->GetArray()+nStartX;
+ SCSIZE nIndex;
+ if ( pThisMarkArr->Search( nStartY, nIndex ) )
+ bCellMarked=pThisMarkArr->pData[nIndex].bMarked;
+ }
+
+ pInfo->bMarked = bCellMarked;
+ }
+ }
+ }
+ }
+
+ if (bAnyShadow) // Schatten verteilen
+ {
+ for (nArrY=0; nArrY<nArrCount; nArrY++)
+ {
+ BOOL bTop = ( nArrY == 0 );
+ BOOL bBottom = ( nArrY+1 == nArrCount );
+
+ for (nArrX=nX1; nArrX<=nX2+2; nArrX++) // links und rechts einer mehr
+ {
+ BOOL bLeft = ( nArrX == nX1 );
+ BOOL bRight = ( nArrX == nX2+2 );
+
+ CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nArrX];
+ const SvxShadowItem* pThisAttr = pInfo->pShadowAttr;
+ SvxShadowLocation eLoc = pThisAttr ? pThisAttr->GetLocation() : SVX_SHADOW_NONE;
+ if (eLoc != SVX_SHADOW_NONE)
+ {
+ // oder Test auf != eLoc
+
+ SCsCOL nDxPos = 1;
+ SCsCOL nDxNeg = -1;
+
+ while ( nArrX+nDxPos < nX2+2 && pRowInfo[0].pCellInfo[nArrX+nDxPos].nWidth == 0 )
+ ++nDxPos;
+ while ( nArrX+nDxNeg > nX1 && pRowInfo[0].pCellInfo[nArrX+nDxNeg].nWidth == 0 )
+ --nDxNeg;
+
+ BOOL bLeftDiff = !bLeft &&
+ CELLINFO(nDxNeg,0).pShadowAttr->GetLocation() == SVX_SHADOW_NONE;
+ BOOL bRightDiff = !bRight &&
+ CELLINFO(nDxPos,0).pShadowAttr->GetLocation() == SVX_SHADOW_NONE;
+ BOOL bTopDiff = !bTop &&
+ CELLINFO(0,-1).pShadowAttr->GetLocation() == SVX_SHADOW_NONE;
+ BOOL bBottomDiff = !bBottom &&
+ CELLINFO(0,1).pShadowAttr->GetLocation() == SVX_SHADOW_NONE;
+
+ if ( bLayoutRTL )
+ {
+ switch (eLoc)
+ {
+ case SVX_SHADOW_BOTTOMRIGHT: eLoc = SVX_SHADOW_BOTTOMLEFT; break;
+ case SVX_SHADOW_BOTTOMLEFT: eLoc = SVX_SHADOW_BOTTOMRIGHT; break;
+ case SVX_SHADOW_TOPRIGHT: eLoc = SVX_SHADOW_TOPLEFT; break;
+ case SVX_SHADOW_TOPLEFT: eLoc = SVX_SHADOW_TOPRIGHT; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+
+ switch (eLoc)
+ {
+ case SVX_SHADOW_BOTTOMRIGHT:
+ if (bBottomDiff)
+ {
+ CELLINFO(0,1).pHShadowOrigin = pThisAttr;
+ CELLINFO(0,1).eHShadowPart =
+ bLeftDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
+ }
+ if (bRightDiff)
+ {
+ CELLINFO(1,0).pVShadowOrigin = pThisAttr;
+ CELLINFO(1,0).eVShadowPart =
+ bTopDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
+ }
+ if (bBottomDiff && bRightDiff)
+ {
+ CELLINFO(1,1).pHShadowOrigin = pThisAttr;
+ CELLINFO(1,1).eHShadowPart = SC_SHADOW_CORNER;
+ }
+ break;
+
+ case SVX_SHADOW_BOTTOMLEFT:
+ if (bBottomDiff)
+ {
+ CELLINFO(0,1).pHShadowOrigin = pThisAttr;
+ CELLINFO(0,1).eHShadowPart =
+ bRightDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
+ }
+ if (bLeftDiff)
+ {
+ CELLINFO(-1,0).pVShadowOrigin = pThisAttr;
+ CELLINFO(-1,0).eVShadowPart =
+ bTopDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
+ }
+ if (bBottomDiff && bLeftDiff)
+ {
+ CELLINFO(-1,1).pHShadowOrigin = pThisAttr;
+ CELLINFO(-1,1).eHShadowPart = SC_SHADOW_CORNER;
+ }
+ break;
+
+ case SVX_SHADOW_TOPRIGHT:
+ if (bTopDiff)
+ {
+ CELLINFO(0,-1).pHShadowOrigin = pThisAttr;
+ CELLINFO(0,-1).eHShadowPart =
+ bLeftDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
+ }
+ if (bRightDiff)
+ {
+ CELLINFO(1,0).pVShadowOrigin = pThisAttr;
+ CELLINFO(1,0).eVShadowPart =
+ bBottomDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
+ }
+ if (bTopDiff && bRightDiff)
+ {
+ CELLINFO(1,-1).pHShadowOrigin = pThisAttr;
+ CELLINFO(1,-1).eHShadowPart = SC_SHADOW_CORNER;
+ }
+ break;
+
+ case SVX_SHADOW_TOPLEFT:
+ if (bTopDiff)
+ {
+ CELLINFO(0,-1).pHShadowOrigin = pThisAttr;
+ CELLINFO(0,-1).eHShadowPart =
+ bRightDiff ? SC_SHADOW_HSTART : SC_SHADOW_HORIZ;
+ }
+ if (bLeftDiff)
+ {
+ CELLINFO(-1,0).pVShadowOrigin = pThisAttr;
+ CELLINFO(-1,0).eVShadowPart =
+ bBottomDiff ? SC_SHADOW_VSTART : SC_SHADOW_VERT;
+ }
+ if (bTopDiff && bLeftDiff)
+ {
+ CELLINFO(-1,-1).pHShadowOrigin = pThisAttr;
+ CELLINFO(-1,-1).eHShadowPart = SC_SHADOW_CORNER;
+ }
+ break;
+
+ default:
+ DBG_ERROR("falscher Shadow-Enum");
+ }
+ }
+ }
+ }
+ }
+
+ rTabInfo.mnArrCount = sal::static_int_cast<USHORT>(nArrCount);
+ rTabInfo.mbPageMode = bPageMode;
+
+ // ========================================================================
+ // *** create the frame border array ***
+
+ // RowInfo structs are filled in the range [ 0 , nArrCount-1 ]
+ // each RowInfo contains CellInfo structs in the range [ nX1-1 , nX2+1 ]
+
+ size_t nColCount = nX2 - nX1 + 3;
+ size_t nRowCount = nArrCount;
+
+ svx::frame::Array& rArray = rTabInfo.maArray;
+ rArray.Initialize( nColCount, nRowCount );
+ rArray.SetUseDiagDoubleClipping( false );
+
+ for( size_t nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ USHORT nCellInfoY = static_cast< USHORT >( nRow );
+ RowInfo& rThisRowInfo = pRowInfo[ nCellInfoY ];
+
+ for( size_t nCol = 0; nCol < nColCount; ++nCol )
+ {
+ USHORT nCellInfoX = static_cast< USHORT >( nCol + nX1 );
+ const CellInfo& rInfo = rThisRowInfo.pCellInfo[ nCellInfoX ];
+
+ const SvxBoxItem* pBox = rInfo.pLinesAttr;
+ const SvxLineItem* pTLBR = rInfo.mpTLBRLine;
+ const SvxLineItem* pBLTR = rInfo.mpBLTRLine;
+
+ size_t nFirstCol = nCol;
+ size_t nFirstRow = nRow;
+
+ // *** merged cells *** -------------------------------------------
+
+ if( !rArray.IsMerged( nCol, nRow ) && (rInfo.bMerged || rInfo.bHOverlapped || rInfo.bVOverlapped) )
+ {
+ // *** insert merged range in svx::frame::Array ***
+
+ /* #i69369# top-left cell of a merged range may be located in
+ a hidden column or row. Use lcl_GetMergeRange() to find the
+ complete merged range, then calculate dimensions and
+ document position of the visible range. */
+
+ // note: document columns are always one less than CellInfoX coords
+ // note: document rows must be looked up in RowInfo structs
+
+ // current column and row in document coordinates
+ SCCOL nCurrDocCol = static_cast< SCCOL >( nCellInfoX - 1 );
+ SCROW nCurrDocRow = static_cast< SCROW >( (nCellInfoY > 0) ? rThisRowInfo.nRowNo : (nY1 - 1) );
+
+ // find entire merged range in document, returns signed document coordinates
+ SCsCOL nFirstRealDocColS, nLastRealDocColS;
+ SCsROW nFirstRealDocRowS, nLastRealDocRowS;
+ lcl_GetMergeRange( static_cast< SCsCOL >( nCurrDocCol ), static_cast< SCsROW >( nCurrDocRow ),
+ nCellInfoY, this, pRowInfo, nX1,nY1,nX2,nY2,nTab,
+ nFirstRealDocColS, nFirstRealDocRowS, nLastRealDocColS, nLastRealDocRowS );
+
+ // *complete* merged range in document coordinates
+ SCCOL nFirstRealDocCol = static_cast< SCCOL >( nFirstRealDocColS );
+ SCROW nFirstRealDocRow = static_cast< SCROW >( nFirstRealDocRowS );
+ SCCOL nLastRealDocCol = static_cast< SCCOL >( nLastRealDocColS );
+ SCROW nLastRealDocRow = static_cast< SCROW >( nLastRealDocRowS );
+
+ // first visible column (nX1-1 is first processed document column)
+ SCCOL nFirstDocCol = (nX1 > 0) ? ::std::max< SCCOL >( nFirstRealDocCol, nX1 - 1 ) : nFirstRealDocCol;
+ USHORT nFirstCellInfoX = static_cast< USHORT >( nFirstDocCol + 1 );
+ nFirstCol = static_cast< size_t >( nFirstCellInfoX - nX1 );
+
+ // last visible column (nX2+1 is last processed document column)
+ SCCOL nLastDocCol = (nX2 < MAXCOL) ? ::std::min< SCCOL >( nLastRealDocCol, nX2 + 1 ) : nLastRealDocCol;
+ USHORT nLastCellInfoX = static_cast< USHORT >( nLastDocCol + 1 );
+ size_t nLastCol = static_cast< size_t >( nLastCellInfoX - nX1 );
+
+ // first visible row
+ USHORT nFirstCellInfoY = nCellInfoY;
+ while( ((nFirstCellInfoY > 1) && (pRowInfo[ nFirstCellInfoY - 1 ].nRowNo >= nFirstRealDocRow)) ||
+ ((nFirstCellInfoY == 1) && (static_cast< SCROW >( nY1 - 1 ) >= nFirstRealDocRow)) )
+ --nFirstCellInfoY;
+ SCROW nFirstDocRow = (nFirstCellInfoY > 0) ? pRowInfo[ nFirstCellInfoY ].nRowNo : static_cast< SCROW >( nY1 - 1 );
+ nFirstRow = static_cast< size_t >( nFirstCellInfoY );
+
+ // last visible row
+ USHORT nLastCellInfoY = nCellInfoY;
+ while( (sal::static_int_cast<SCSIZE>(nLastCellInfoY + 1) < nArrCount) &&
+ (pRowInfo[ nLastCellInfoY + 1 ].nRowNo <= nLastRealDocRow) )
+ ++nLastCellInfoY;
+ SCROW nLastDocRow = (nLastCellInfoY > 0) ? pRowInfo[ nLastCellInfoY ].nRowNo : static_cast< SCROW >( nY1 - 1 );
+ size_t nLastRow = static_cast< size_t >( nLastCellInfoY );
+
+ // insert merged range
+ rArray.SetMergedRange( nFirstCol, nFirstRow, nLastCol, nLastRow );
+
+ // *** find additional size not included in svx::frame::Array ***
+
+ // additional space before first column
+ if( nFirstCol == 0 )
+ {
+ long nSize = 0;
+ for( SCCOL nDocCol = nFirstRealDocCol; nDocCol < nFirstDocCol; ++nDocCol )
+ nSize += std::max( static_cast< long >( GetColWidth( nDocCol, nTab ) * nScaleX ), 1L );
+ rArray.SetAddMergedLeftSize( nCol, nRow, nSize );
+ }
+ // additional space after last column
+ if( nLastCol + 1 == nColCount )
+ {
+ long nSize = 0;
+ for( SCCOL nDocCol = nLastDocCol + 1; nDocCol <= nLastRealDocCol; ++nDocCol )
+ nSize += std::max( static_cast< long >( GetColWidth( nDocCol, nTab ) * nScaleX ), 1L );
+ rArray.SetAddMergedRightSize( nCol, nRow, nSize );
+ }
+ // additional space above first row
+ if( nFirstRow == 0 )
+ {
+ long nSize = 0;
+ for( SCROW nDocRow = nFirstRealDocRow; nDocRow < nFirstDocRow; ++nDocRow )
+ nSize += std::max( static_cast< long >( GetRowHeight( nDocRow, nTab ) * nScaleY ), 1L );
+ rArray.SetAddMergedTopSize( nCol, nRow, nSize );
+ }
+ // additional space beyond last row
+ if( nLastRow + 1 == nRowCount )
+ {
+ long nSize = 0;
+ for( SCROW nDocRow = nLastDocRow + 1; nDocRow <= nLastRealDocRow; ++nDocRow )
+ nSize += std::max( static_cast< long >( GetRowHeight( nDocRow, nTab ) * nScaleY ), 1L );
+ rArray.SetAddMergedBottomSize( nCol, nRow, nSize );
+ }
+
+ // *** use line attributes from real origin cell ***
+
+ if( (nFirstRealDocCol != nCurrDocCol) || (nFirstRealDocRow != nCurrDocRow) )
+ {
+ if( const ScPatternAttr* pPattern = GetPattern( nFirstRealDocCol, nFirstRealDocRow, nTab ) )
+ {
+ const SfxItemSet* pCond = GetCondResult( nFirstRealDocCol, nFirstRealDocRow, nTab );
+ pBox = static_cast< const SvxBoxItem* >( &pPattern->GetItem( ATTR_BORDER, pCond ) );
+ pTLBR = static_cast< const SvxLineItem* >( &pPattern->GetItem( ATTR_BORDER_TLBR, pCond ) );
+ pBLTR = static_cast< const SvxLineItem* >( &pPattern->GetItem( ATTR_BORDER_BLTR, pCond ) );
+ }
+ else
+ {
+ pBox = 0;
+ pTLBR = pBLTR = 0;
+ }
+ }
+ }
+
+ // *** borders *** ------------------------------------------------
+
+ if( pBox )
+ {
+ rArray.SetCellStyleLeft( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetLeft(), nScaleX ) );
+ rArray.SetCellStyleRight( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetRight(), nScaleX ) );
+ rArray.SetCellStyleTop( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetTop(), nScaleY ) );
+ rArray.SetCellStyleBottom( nFirstCol, nFirstRow, svx::frame::Style( pBox->GetBottom(), nScaleY ) );
+ }
+
+ if( pTLBR )
+ rArray.SetCellStyleTLBR( nFirstCol, nFirstRow, svx::frame::Style( pTLBR->GetLine(), nScaleY ) );
+ if( rInfo.mpBLTRLine )
+ rArray.SetCellStyleBLTR( nFirstCol, nFirstRow, svx::frame::Style( pBLTR->GetLine(), nScaleY ) );
+ }
+ }
+
+ /* Mirror the entire frame array.
+ 1st param = Mirror the vertical double line styles as well.
+ 2nd param = Do not swap diagonal lines.
+ */
+ if( bLayoutRTL )
+ rArray.MirrorSelfX( true, false );
+}
+
+// ============================================================================
+
+ScTableInfo::ScTableInfo() :
+ mpRowInfo( new RowInfo[ ROWINFO_MAX ] ),
+ mbPageMode( false )
+{
+ for( USHORT nIdx = 0; nIdx < ROWINFO_MAX; ++nIdx )
+ mpRowInfo[ nIdx ].pCellInfo = 0;
+}
+
+ScTableInfo::~ScTableInfo()
+{
+ for( USHORT nIdx = 0; nIdx < ROWINFO_MAX; ++nIdx )
+ delete [] mpRowInfo[ nIdx ].pCellInfo;
+ delete [] mpRowInfo;
+}
+
+// ============================================================================
+
diff --git a/sc/source/core/data/global.cxx b/sc/source/core/data/global.cxx
new file mode 100644
index 000000000000..3320e9a9a95c
--- /dev/null
+++ b/sc/source/core/data/global.cxx
@@ -0,0 +1,1964 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: global.cxx,v $
+ * $Revision: 1.56.102.1 $
+ *
+ * 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 ---------------------------------------------------------------
+#include <vcl/svapp.hxx>
+#include "scitems.hxx"
+#include <svx/algitem.hxx>
+#include <svx/brshitem.hxx>
+#include <svx/editobj.hxx>
+#include <svx/scripttypeitem.hxx>
+#include <svx/srchitem.hxx>
+#include <svx/langitem.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svtools/stritem.hxx>
+#include <svtools/zforlist.hxx>
+#include <svtools/zformat.hxx>
+#include <vcl/image.hxx>
+#include <vcl/virdev.hxx>
+#include <tools/rcid.h>
+#include <unotools/charclass.hxx>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <numeric>
+
+
+#include <i18npool/mslangid.hxx>
+#include <com/sun/star/lang/Locale.hpp>
+#include <comphelper/processfactory.hxx>
+#include <unotools/calendarwrapper.hxx>
+#include <unotools/collatorwrapper.hxx>
+#include <com/sun/star/i18n/CollatorOptions.hpp>
+#include <unotools/intlwrapper.hxx>
+#include <svtools/syslocale.hxx>
+#include <unotools/transliterationwrapper.hxx>
+
+#include "global.hxx"
+#include "scresid.hxx"
+#include "autoform.hxx"
+#include "document.hxx"
+#include "patattr.hxx"
+#include "addincol.hxx"
+#include "adiasync.hxx"
+#include "userlist.hxx"
+#include "interpre.hxx"
+#include "strload.hxx"
+#include "docpool.hxx"
+#include "unitconv.hxx"
+#include "compiler.hxx"
+#include "parclass.hxx"
+#include "funcdesc.hxx"
+#include "globstr.hrc"
+#include "scfuncs.hrc"
+#include "sc.hrc"
+#include "scmod.hxx"
+#include "appoptio.hxx"
+
+// -----------------------------------------------------------------------
+
+#define CLIPST_AVAILABLE 0
+#define CLIPST_CAPTURED 1
+#define CLIPST_DELETE 2
+#define CLIPST_DRAW 3
+
+ScDocShellRef* ScGlobal::pDrawClipDocShellRef = NULL;
+SvxSearchItem* ScGlobal::pSearchItem = NULL;
+ScAutoFormat* ScGlobal::pAutoFormat = NULL;
+FuncCollection* ScGlobal::pFuncCollection = NULL;
+ScUnoAddInCollection* ScGlobal::pAddInCollection = NULL;
+ScUserList* ScGlobal::pUserList = NULL;
+String** ScGlobal::ppRscString = NULL;
+LanguageType ScGlobal::eLnge = LANGUAGE_SYSTEM;
+::com::sun::star::lang::Locale* ScGlobal::pLocale = NULL;
+SvtSysLocale* ScGlobal::pSysLocale = NULL;
+const CharClass* ScGlobal::pCharClass = NULL;
+const LocaleDataWrapper* ScGlobal::pLocaleData = NULL;
+CalendarWrapper* ScGlobal::pCalendar = NULL;
+CollatorWrapper* ScGlobal::pCollator = NULL;
+CollatorWrapper* ScGlobal::pCaseCollator = NULL;
+::utl::TransliterationWrapper* ScGlobal::pTransliteration = NULL;
+::utl::TransliterationWrapper* ScGlobal::pCaseTransliteration = NULL;
+::com::sun::star::uno::Reference< ::com::sun::star::i18n::XOrdinalSuffix> ScGlobal::xOrdinalSuffix = NULL;
+IntlWrapper* ScGlobal::pScIntlWrapper = NULL;
+sal_Unicode ScGlobal::cListDelimiter = ',';
+String* ScGlobal::pEmptyString = NULL;
+String* ScGlobal::pStrClipDocName = NULL;
+
+SvxBrushItem* ScGlobal::pEmptyBrushItem = NULL;
+SvxBrushItem* ScGlobal::pButtonBrushItem = NULL;
+SvxBrushItem* ScGlobal::pEmbeddedBrushItem = NULL;
+SvxBrushItem* ScGlobal::pProtectedBrushItem = NULL;
+
+ImageList* ScGlobal::pOutlineBitmaps = NULL;
+ImageList* ScGlobal::pOutlineBitmapsHC = NULL;
+
+ScFunctionList* ScGlobal::pStarCalcFunctionList = NULL;
+ScFunctionMgr* ScGlobal::pStarCalcFunctionMgr = NULL;
+
+ScUnitConverter* ScGlobal::pUnitConverter = NULL;
+SvNumberFormatter* ScGlobal::pEnglishFormatter = NULL;
+
+double ScGlobal::nScreenPPTX = 96.0;
+double ScGlobal::nScreenPPTY = 96.0;
+
+USHORT ScGlobal::nDefFontHeight = 240;
+USHORT ScGlobal::nStdRowHeight = 257;
+
+long ScGlobal::nLastRowHeightExtra = 0;
+long ScGlobal::nLastColWidthExtra = STD_EXTRA_WIDTH;
+
+static USHORT nPPTZoom = 0; // ScreenZoom used to determine nScreenPPTX/Y
+
+
+// ... oder so?
+
+BOOL bOderSo;
+
+bool SC_DLLPUBLIC ScGetWriteTeamInfo()
+{
+ return bOderSo;
+}
+
+class SfxViewShell;
+SfxViewShell* pScActiveViewShell = NULL; //! als Member !!!!!
+USHORT nScClickMouseModifier = 0; //! dito
+USHORT nScFillModeMouseModifier = 0; //! dito
+
+// Hack: ScGlobal::GetUserList() muss InitAppOptions in der UI aufrufen,
+// damit UserList aus Cfg geladen wird
+
+void global_InitAppOptions();
+
+//========================================================================
+//
+// statische Funktionen
+//
+//========================================================================
+
+BOOL ScGlobal::HasAttrChanged( const SfxItemSet& rNewAttrs,
+ const SfxItemSet& rOldAttrs,
+ const USHORT nWhich )
+{
+ BOOL bInvalidate = FALSE;
+ const SfxItemState eNewState = rNewAttrs.GetItemState( nWhich );
+ const SfxItemState eOldState = rOldAttrs.GetItemState( nWhich );
+
+ //----------------------------------------------------------
+
+ if ( eNewState == eOldState )
+ {
+ // beide Items gesetzt
+ // PoolItems, d.h. Pointer-Vergleich zulaessig
+ if ( SFX_ITEM_SET == eOldState )
+ bInvalidate = (&rNewAttrs.Get( nWhich ) != &rOldAttrs.Get( nWhich ));
+ }
+ else
+ {
+ // ein Default-Item dabei
+ // PoolItems, d.h. Item-Vergleich noetig
+
+ const SfxPoolItem& rOldItem = ( SFX_ITEM_SET == eOldState )
+ ? rOldAttrs.Get( nWhich )
+ : rOldAttrs.GetPool()->GetDefaultItem( nWhich );
+
+ const SfxPoolItem& rNewItem = ( SFX_ITEM_SET == eNewState )
+ ? rNewAttrs.Get( nWhich )
+ : rNewAttrs.GetPool()->GetDefaultItem( nWhich );
+
+ bInvalidate = sal::static_int_cast<BOOL>(rNewItem != rOldItem);
+ }
+
+ return bInvalidate;
+}
+
+ULONG ScGlobal::GetStandardFormat( SvNumberFormatter& rFormatter,
+ ULONG nFormat, short nType )
+{
+ const SvNumberformat* pFormat = rFormatter.GetEntry( nFormat );
+ if ( pFormat )
+ return rFormatter.GetStandardFormat( nFormat, nType, pFormat->GetLanguage() );
+ return rFormatter.GetStandardFormat( nType, eLnge );
+}
+
+ULONG ScGlobal::GetStandardFormat( double fNumber, SvNumberFormatter& rFormatter,
+ ULONG nFormat, short nType )
+{
+ const SvNumberformat* pFormat = rFormatter.GetEntry( nFormat );
+ if ( pFormat )
+ return rFormatter.GetStandardFormat( fNumber, nFormat, nType,
+ pFormat->GetLanguage() );
+ return rFormatter.GetStandardFormat( nType, eLnge );
+}
+
+
+// static
+SvNumberFormatter* ScGlobal::GetEnglishFormatter()
+{
+ if ( !pEnglishFormatter )
+ {
+ pEnglishFormatter = new SvNumberFormatter(
+ ::comphelper::getProcessServiceFactory(), LANGUAGE_ENGLISH_US );
+ pEnglishFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_INTL_FORMAT );
+ }
+ return pEnglishFormatter;
+}
+
+
+//------------------------------------------------------------------------
+
+BOOL ScGlobal::CheckWidthInvalidate( BOOL& bNumFormatChanged,
+ const SfxItemSet& rNewAttrs,
+ const SfxItemSet& rOldAttrs )
+{
+ // Ueberpruefen, ob Attributaenderungen in rNewAttrs gegnueber
+ // rOldAttrs die Textbreite an einer Zelle ungueltig machen
+
+ bNumFormatChanged =
+ HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_VALUE_FORMAT );
+ return ( bNumFormatChanged
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_LANGUAGE_FORMAT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CJK_FONT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CTL_FONT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_HEIGHT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CJK_FONT_HEIGHT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CTL_FONT_HEIGHT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_WEIGHT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CJK_FONT_WEIGHT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CTL_FONT_WEIGHT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_POSTURE )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CJK_FONT_POSTURE )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_CTL_FONT_POSTURE )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_UNDERLINE )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_OVERLINE )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_CROSSEDOUT )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_CONTOUR )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_FONT_SHADOWED )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_STACKED )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_ROTATE_VALUE )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_ROTATE_MODE )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_LINEBREAK )
+ || HasAttrChanged( rNewAttrs, rOldAttrs, ATTR_MARGIN )
+ );
+}
+
+const SvxSearchItem& ScGlobal::GetSearchItem()
+{
+ if (!pSearchItem)
+ {
+ pSearchItem = new SvxSearchItem( SID_SEARCH_ITEM );
+ pSearchItem->SetAppFlag( SVX_SEARCHAPP_CALC );
+ }
+ return *pSearchItem;
+}
+
+void ScGlobal::SetSearchItem( const SvxSearchItem& rNew )
+{
+ // Hier waere ein Zuweisungsoperator ganz nett:
+ delete pSearchItem;
+ pSearchItem = (SvxSearchItem*)rNew.Clone();
+
+ pSearchItem->SetWhich( SID_SEARCH_ITEM );
+}
+
+void ScGlobal::ClearAutoFormat()
+{
+ if (pAutoFormat!=NULL)
+ {
+ delete pAutoFormat;
+ pAutoFormat=NULL;
+ }
+}
+
+ScAutoFormat* ScGlobal::GetAutoFormat()
+{
+ if ( !pAutoFormat )
+ {
+ pAutoFormat = new ScAutoFormat;
+ pAutoFormat->Load();
+ }
+
+ return pAutoFormat;
+}
+
+FuncCollection* ScGlobal::GetFuncCollection()
+{
+ if (!pFuncCollection)
+ pFuncCollection = new FuncCollection();
+ return pFuncCollection;
+}
+
+ScUnoAddInCollection* ScGlobal::GetAddInCollection()
+{
+ if (!pAddInCollection)
+ pAddInCollection = new ScUnoAddInCollection();
+ return pAddInCollection;
+}
+
+ScUserList* ScGlobal::GetUserList()
+{
+ // Hack: Cfg-Item an der App ggF. laden
+
+ global_InitAppOptions();
+
+ if (!pUserList)
+ pUserList = new ScUserList();
+ return pUserList;
+}
+
+void ScGlobal::SetUserList( const ScUserList* pNewList )
+{
+ if ( pNewList )
+ {
+ if ( !pUserList )
+ pUserList = new ScUserList( *pNewList );
+ else
+ *pUserList = *pNewList;
+ }
+ else
+ {
+ delete pUserList;
+ pUserList = NULL;
+ }
+}
+
+const String& ScGlobal::GetRscString( USHORT nIndex )
+{
+ DBG_ASSERT( nIndex < STR_COUNT, "ScGlobal::GetRscString - invalid string index");
+ if( !ppRscString[ nIndex ] )
+ {
+ OpCode eOp = ocNone;
+ // Map former globstr.src strings moved to compiler.src
+ switch (nIndex)
+ {
+ case STR_NULL_ERROR:
+ eOp = ocErrNull;
+ break;
+ case STR_DIV_ZERO:
+ eOp = ocErrDivZero;
+ break;
+ case STR_NO_VALUE:
+ eOp = ocErrValue;
+ break;
+ case STR_NOREF_STR:
+ eOp = ocErrRef;
+ break;
+ case STR_NO_NAME_REF:
+ eOp = ocErrName;
+ break;
+ case STR_NUM_ERROR:
+ eOp = ocErrNum;
+ break;
+ case STR_NV_STR:
+ eOp = ocErrNA;
+ break;
+ default:
+ ; // nothing
+ }
+ if (eOp != ocNone)
+ ppRscString[ nIndex ] = new String(
+ ScCompiler::GetNativeSymbol( eOp));
+ else
+ ppRscString[ nIndex ] = new String(
+ ScRscStrLoader( RID_GLOBSTR, nIndex ).GetString());
+ }
+ return *ppRscString[ nIndex ];
+}
+
+String ScGlobal::GetErrorString(USHORT nErrNumber)
+{
+ String sResStr;
+ switch (nErrNumber)
+ {
+ case NOTAVAILABLE : nErrNumber = STR_NV_STR; break;
+ case errNoRef : nErrNumber = STR_NO_REF_TABLE; break;
+ case errNoName : nErrNumber = STR_NO_NAME_REF; break;
+ case errNoAddin : nErrNumber = STR_NO_ADDIN; break;
+ case errNoMacro : nErrNumber = STR_NO_MACRO; break;
+ case errDoubleRef :
+ case errNoValue : nErrNumber = STR_NO_VALUE; break;
+ case errNoCode : nErrNumber = STR_NULL_ERROR; break;
+ case errDivisionByZero : nErrNumber = STR_DIV_ZERO; break;
+ case errIllegalFPOperation : nErrNumber = STR_NUM_ERROR; break;
+
+ default : sResStr = GetRscString(STR_ERROR_STR);
+ sResStr += String::CreateFromInt32( nErrNumber );
+ nErrNumber = 0;
+ break;
+ }
+ if( nErrNumber )
+ sResStr = GetRscString( nErrNumber );
+ return sResStr;
+}
+
+String ScGlobal::GetLongErrorString(USHORT nErrNumber)
+{
+ switch (nErrNumber)
+ {
+ case 0:
+ break;
+ case 1:
+ case errIllegalArgument:
+ nErrNumber = STR_LONG_ERR_ILL_ARG;
+ break;
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case errIllegalFPOperation:
+ nErrNumber = STR_LONG_ERR_ILL_FPO;
+ break;
+ case errIllegalChar:
+ nErrNumber = STR_LONG_ERR_ILL_CHAR;
+ break;
+ case errIllegalParameter:
+ nErrNumber = STR_LONG_ERR_ILL_PAR;
+ break;
+ case errSeparator:
+ nErrNumber = STR_LONG_ERR_ILL_SEP;
+ break;
+ case errPair:
+ case errPairExpected:
+ nErrNumber = STR_LONG_ERR_PAIR;
+ break;
+ case errOperatorExpected:
+ nErrNumber = STR_LONG_ERR_OP_EXP;
+ break;
+ case errVariableExpected:
+ case errParameterExpected:
+ nErrNumber = STR_LONG_ERR_VAR_EXP;
+ break;
+ case errCodeOverflow:
+ nErrNumber = STR_LONG_ERR_CODE_OVF;
+ break;
+ case errStringOverflow:
+ nErrNumber = STR_LONG_ERR_STR_OVF;
+ break;
+ case errStackOverflow:
+ case errInterpOverflow:
+ nErrNumber = STR_LONG_ERR_STACK_OVF;
+ break;
+ case errIllegalJump:
+ case errUnknownState:
+ case errUnknownVariable:
+ case errUnknownOpCode:
+ case errUnknownStackVariable:
+ case errUnknownToken:
+ case errNoCode:
+ case errDoubleRef:
+ nErrNumber = STR_LONG_ERR_SYNTAX;
+ break;
+ case errCircularReference:
+ nErrNumber = STR_LONG_ERR_CIRC_REF;
+ break;
+ case errNoConvergence:
+ nErrNumber = STR_LONG_ERR_NO_CONV;
+ break;
+ case errNoRef:
+ nErrNumber = STR_LONG_ERR_NO_REF;
+ break;
+ case errNoName:
+ nErrNumber = STR_LONG_ERR_NO_NAME;
+ break;
+ case errNoAddin:
+ nErrNumber = STR_LONG_ERR_NO_ADDIN;
+ break;
+ case errNoMacro:
+ nErrNumber = STR_LONG_ERR_NO_MACRO;
+ break;
+ case errDivisionByZero:
+ nErrNumber = STR_LONG_ERR_DIV_ZERO;
+ break;
+ case errNestedArray:
+ nErrNumber = STR_ERR_LONG_NESTED_ARRAY;
+ break;
+ case errNoValue:
+ nErrNumber = STR_LONG_ERR_NO_VALUE;
+ break;
+ case NOTAVAILABLE:
+ nErrNumber = STR_LONG_ERR_NV;
+ break;
+ default:
+ nErrNumber = STR_ERROR_STR;
+ break;
+ }
+ String aRes( GetRscString( nErrNumber ) );
+ if( bOderSo )
+ {
+ String aOderSo( GetRscString( STR_ODER_SO ) );
+ aOderSo.SearchAndReplace( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("%s")), aRes );
+ aRes = aOderSo;
+ }
+ return aRes;
+}
+
+SvxBrushItem* ScGlobal::GetButtonBrushItem()
+{
+ pButtonBrushItem->SetColor( Application::GetSettings().GetStyleSettings().GetFaceColor() );
+ return pButtonBrushItem;
+}
+
+const String& ScGlobal::GetEmptyString()
+{
+ return *pEmptyString;
+}
+
+ImageList* ScGlobal::GetOutlineSymbols( bool bHC )
+{
+ ImageList*& rpImageList = bHC ? pOutlineBitmapsHC : pOutlineBitmaps;
+ if( !rpImageList )
+ rpImageList = new ImageList( ScResId( bHC ? RID_OUTLINEBITMAPS_H : RID_OUTLINEBITMAPS ) );
+ return rpImageList;
+}
+
+void ScGlobal::Init()
+{
+ pEmptyString = new String;
+
+ // Die Default-Sprache fuer Zahlenformate (ScGlobal::eLnge)
+ // muss immer LANGUAGE_SYSTEM sein
+ //! Dann kann auch die Variable raus
+ eLnge = LANGUAGE_SYSTEM;
+
+ //! Wenn Sortierung etc. von der Sprache der installierten Offfice-Version
+ //! abhaengen sollen, hier "Application::GetSettings().GetUILanguage()"
+ LanguageType eOfficeLanguage = Application::GetSettings().GetLanguage();
+ pLocale = new ::com::sun::star::lang::Locale( Application::GetSettings().GetLocale());
+ pSysLocale = new SvtSysLocale;
+ pCharClass = pSysLocale->GetCharClassPtr();
+ pLocaleData = pSysLocale->GetLocaleDataPtr();
+ pCalendar = new CalendarWrapper( ::comphelper::getProcessServiceFactory() );
+ pCalendar->loadDefaultCalendar( *pLocale );
+ pCollator = new CollatorWrapper( ::comphelper::getProcessServiceFactory() );
+ pCollator->loadDefaultCollator( *pLocale, SC_COLLATOR_IGNORES );
+ pCaseCollator = new CollatorWrapper( ::comphelper::getProcessServiceFactory() );
+ pCaseCollator->loadDefaultCollator( *pLocale, 0 );
+ pTransliteration = new ::utl::TransliterationWrapper(
+ ::comphelper::getProcessServiceFactory(), SC_TRANSLITERATION_IGNORECASE );
+ pTransliteration->loadModuleIfNeeded( eOfficeLanguage );
+ pCaseTransliteration = new ::utl::TransliterationWrapper(
+ ::comphelper::getProcessServiceFactory(), SC_TRANSLITERATION_CASESENSE );
+ pCaseTransliteration->loadModuleIfNeeded( eOfficeLanguage );
+ pScIntlWrapper = new IntlWrapper( ::comphelper::getProcessServiceFactory(), *pLocale );
+
+ ppRscString = new String *[ STR_COUNT ];
+ for( USHORT nC = 0 ; nC < STR_COUNT ; nC++ ) ppRscString[ nC ] = NULL;
+
+ pEmptyBrushItem = new SvxBrushItem( Color( COL_TRANSPARENT ), ATTR_BACKGROUND );
+ pButtonBrushItem = new SvxBrushItem( Color(), ATTR_BACKGROUND );
+ pEmbeddedBrushItem = new SvxBrushItem( Color( COL_LIGHTCYAN ), ATTR_BACKGROUND );
+ pProtectedBrushItem = new SvxBrushItem( Color( COL_LIGHTGRAY ), ATTR_BACKGROUND );
+
+ UpdatePPT(NULL);
+ //ScCompiler::InitSymbolsNative();
+ // ScParameterClassification _after_ Compiler, needs function resources if
+ // arguments are to be merged in, which in turn need strings of function
+ // names from the compiler.
+ ScParameterClassification::Init();
+ srand( (unsigned) time( NULL ) ); // Random Seed Init fuer Interpreter
+
+ InitAddIns();
+
+ pStrClipDocName = new String( ScResId( SCSTR_NONAME ) );
+ *pStrClipDocName += '1';
+
+ // ScDocumentPool::InitVersionMaps() ist schon vorher gerufen worden
+}
+
+void ScGlobal::UpdatePPT( OutputDevice* pDev )
+{
+ USHORT nCurrentZoom = Application::GetSettings().GetStyleSettings().GetScreenZoom();
+ if ( nCurrentZoom != nPPTZoom )
+ {
+ // Screen PPT values must be updated when ScreenZoom has changed.
+ // If called from Window::DataChanged, the window is passed as pDev,
+ // to make sure LogicToPixel uses a device which already uses the new zoom.
+ // For the initial settings, NULL is passed and GetDefaultDevice used.
+
+ if ( !pDev )
+ pDev = Application::GetDefaultDevice();
+ Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP );
+ nScreenPPTX = aPix1000.X() / 1000.0;
+ nScreenPPTY = aPix1000.Y() / 1000.0;
+ nPPTZoom = nCurrentZoom;
+ }
+}
+
+const String& ScGlobal::GetClipDocName()
+{
+ return *pStrClipDocName;
+}
+
+void ScGlobal::SetClipDocName( const String& rNew )
+{
+ *pStrClipDocName = rNew;
+}
+
+
+void ScGlobal::InitTextHeight(SfxItemPool* pPool)
+{
+ if (!pPool)
+ {
+ DBG_ERROR("kein Pool bei ScGlobal::InitTextHeight");
+ return;
+ }
+
+ const ScPatternAttr* pPattern = (const ScPatternAttr*)&pPool->GetDefaultItem(ATTR_PATTERN);
+ if (!pPattern)
+ {
+ DBG_ERROR("kein Default-Pattern bei ScGlobal::InitTextHeight");
+ return;
+ }
+
+// String aTestString('X');
+ OutputDevice* pDefaultDev = Application::GetDefaultDevice();
+ VirtualDevice aVirtWindow( *pDefaultDev );
+ aVirtWindow.SetMapMode(MAP_PIXEL);
+ Font aDefFont;
+ pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, &aVirtWindow); // font color doesn't matter here
+ aVirtWindow.SetFont(aDefFont);
+ nDefFontHeight = (USHORT) aVirtWindow.PixelToLogic(Size(0, aVirtWindow.GetTextHeight()),
+ MAP_TWIP).Height();
+
+ const SvxMarginItem* pMargin = (const SvxMarginItem*)&pPattern->GetItem(ATTR_MARGIN);
+
+ nStdRowHeight = (USHORT) ( nDefFontHeight +
+ pMargin->GetTopMargin() + pMargin->GetBottomMargin()
+ - STD_ROWHEIGHT_DIFF );
+}
+
+void ScGlobal::Clear()
+{
+ // asyncs _vor_ ExitExternalFunc zerstoeren!
+ theAddInAsyncTbl.DeleteAndDestroy( 0, theAddInAsyncTbl.Count() );
+ ExitExternalFunc();
+ DELETEZ(pAutoFormat);
+ DELETEZ(pSearchItem);
+ DELETEZ(pFuncCollection);
+ DELETEZ(pAddInCollection);
+ DELETEZ(pUserList);
+
+ for( USHORT nC = 0 ; nC < STR_COUNT ; nC++ )
+ if( ppRscString ) delete ppRscString[ nC ];
+ delete[] ppRscString;
+ ppRscString = NULL;
+
+ DELETEZ(pStarCalcFunctionList); // vor ResMgr zerstoeren!
+ DELETEZ(pStarCalcFunctionMgr);
+ ScParameterClassification::Exit();
+ ScCompiler::DeInit();
+ ScInterpreter::GlobalExit(); // statischen Stack loeschen
+
+ DELETEZ(pEmptyBrushItem);
+ DELETEZ(pButtonBrushItem);
+ DELETEZ(pEmbeddedBrushItem);
+ DELETEZ(pProtectedBrushItem);
+ DELETEZ(pOutlineBitmaps);
+ DELETEZ(pOutlineBitmapsHC);
+// DELETEZ(pAnchorBitmap);
+// DELETEZ(pGrayAnchorBitmap);
+ DELETEZ(pEnglishFormatter);
+ DELETEZ(pCaseTransliteration);
+ DELETEZ(pTransliteration);
+ DELETEZ(pCaseCollator);
+ DELETEZ(pCollator);
+ DELETEZ(pCalendar);
+ //! do NOT delete pCharClass since it is a pointer to the single SvtSysLocale instance
+ pCharClass = NULL;
+ //! do NOT delete pLocaleData since it is a pointer to the single SvtSysLocale instance
+ pLocaleData = NULL;
+ DELETEZ(pSysLocale);
+ DELETEZ(pLocale);
+ DELETEZ(pScIntlWrapper);
+ DELETEZ(pStrClipDocName);
+
+ DELETEZ(pUnitConverter);
+
+ ScDocumentPool::DeleteVersionMaps();
+
+ DELETEZ(pEmptyString);
+}
+
+//------------------------------------------------------------------------
+
+// static
+CharSet ScGlobal::GetCharsetValue( const String& rCharSet )
+{
+ // new TextEncoding values
+ if ( CharClass::isAsciiNumeric( rCharSet ) )
+ {
+ sal_Int32 nVal = rCharSet.ToInt32();
+ if ( !nVal || nVal == RTL_TEXTENCODING_DONTKNOW )
+ return gsl_getSystemTextEncoding();
+ return (CharSet) nVal;
+ }
+ // old CharSet values for compatibility
+ else if (rCharSet.EqualsIgnoreCaseAscii("ANSI") ) return RTL_TEXTENCODING_MS_1252;
+ else if (rCharSet.EqualsIgnoreCaseAscii("MAC") ) return RTL_TEXTENCODING_APPLE_ROMAN;
+ else if (rCharSet.EqualsIgnoreCaseAscii("IBMPC") ) return RTL_TEXTENCODING_IBM_850;
+ else if (rCharSet.EqualsIgnoreCaseAscii("IBMPC_437")) return RTL_TEXTENCODING_IBM_437;
+ else if (rCharSet.EqualsIgnoreCaseAscii("IBMPC_850")) return RTL_TEXTENCODING_IBM_850;
+ else if (rCharSet.EqualsIgnoreCaseAscii("IBMPC_860")) return RTL_TEXTENCODING_IBM_860;
+ else if (rCharSet.EqualsIgnoreCaseAscii("IBMPC_861")) return RTL_TEXTENCODING_IBM_861;
+ else if (rCharSet.EqualsIgnoreCaseAscii("IBMPC_863")) return RTL_TEXTENCODING_IBM_863;
+ else if (rCharSet.EqualsIgnoreCaseAscii("IBMPC_865")) return RTL_TEXTENCODING_IBM_865;
+// else if (rCharSet.EqualsIgnoreCaseAscii("SYSTEM") ) return gsl_getSystemTextEncoding();
+ else return gsl_getSystemTextEncoding();
+}
+
+//------------------------------------------------------------------------
+
+// static
+String ScGlobal::GetCharsetString( CharSet eVal )
+{
+ const sal_Char* pChar;
+ switch ( eVal )
+ {
+ // old CharSet strings for compatibility
+ case RTL_TEXTENCODING_MS_1252: pChar = "ANSI"; break;
+ case RTL_TEXTENCODING_APPLE_ROMAN: pChar = "MAC"; break;
+ // IBMPC == IBMPC_850
+ case RTL_TEXTENCODING_IBM_437: pChar = "IBMPC_437"; break;
+ case RTL_TEXTENCODING_IBM_850: pChar = "IBMPC_850"; break;
+ case RTL_TEXTENCODING_IBM_860: pChar = "IBMPC_860"; break;
+ case RTL_TEXTENCODING_IBM_861: pChar = "IBMPC_861"; break;
+ case RTL_TEXTENCODING_IBM_863: pChar = "IBMPC_863"; break;
+ case RTL_TEXTENCODING_IBM_865: pChar = "IBMPC_865"; break;
+ case RTL_TEXTENCODING_DONTKNOW: pChar = "SYSTEM"; break;
+ // new string of TextEncoding value
+ default:
+ return String::CreateFromInt32( eVal );
+ }
+ return String::CreateFromAscii(pChar);
+}
+
+//------------------------------------------------------------------------
+
+bool ScGlobal::HasStarCalcFunctionList()
+{
+ return ( pStarCalcFunctionList != NULL );
+}
+
+ScFunctionList* ScGlobal::GetStarCalcFunctionList()
+{
+ if ( !pStarCalcFunctionList )
+ pStarCalcFunctionList = new ScFunctionList;
+
+ return pStarCalcFunctionList;
+}
+
+//------------------------------------------------------------------------
+
+ScFunctionMgr* ScGlobal::GetStarCalcFunctionMgr()
+{
+ if ( !pStarCalcFunctionMgr )
+ pStarCalcFunctionMgr = new ScFunctionMgr;
+
+ return pStarCalcFunctionMgr;
+}
+
+void ScGlobal::ResetFunctionList()
+{
+ // FunctionMgr has pointers into FunctionList, must also be updated
+
+ DELETEZ( pStarCalcFunctionMgr );
+ DELETEZ( pStarCalcFunctionList );
+}
+
+//------------------------------------------------------------------------
+
+// static
+ScUnitConverter* ScGlobal::GetUnitConverter()
+{
+ if ( !pUnitConverter )
+ pUnitConverter = new ScUnitConverter;
+
+ return pUnitConverter;
+}
+
+
+//------------------------------------------------------------------------
+
+// static
+const sal_Unicode* ScGlobal::UnicodeStrChr( const sal_Unicode* pStr,
+ sal_Unicode c )
+{
+ if ( !pStr )
+ return NULL;
+ while ( *pStr )
+ {
+ if ( *pStr == c )
+ return pStr;
+ pStr++;
+ }
+ return NULL;
+}
+
+// ----------------------------------------------------------------------------
+
+void ScGlobal::AddToken( String& rTokenList, const String& rToken, sal_Unicode cSep, xub_StrLen nSepCount, bool bForceSep )
+{
+ if( bForceSep || (rToken.Len() && rTokenList.Len()) )
+ rTokenList.Expand( rTokenList.Len() + nSepCount, cSep );
+ rTokenList.Append( rToken );
+}
+
+bool ScGlobal::IsQuoted( const String& rString, sal_Unicode cQuote )
+{
+ return (rString.Len() >= 2) && (rString.GetChar( 0 ) == cQuote) && (rString.GetChar( rString.Len() - 1 ) == cQuote);
+}
+
+void ScGlobal::AddQuotes( String& rString, sal_Unicode cQuote, bool bEscapeEmbedded )
+{
+ if (bEscapeEmbedded)
+ {
+ sal_Unicode pQ[3];
+ pQ[0] = pQ[1] = cQuote;
+ pQ[2] = 0;
+ String aQuotes( pQ );
+ rString.SearchAndReplaceAll( cQuote, aQuotes);
+ }
+ rString.Insert( cQuote, 0 ).Append( cQuote );
+}
+
+void ScGlobal::EraseQuotes( String& rString, sal_Unicode cQuote, bool bUnescapeEmbedded )
+{
+ if ( IsQuoted( rString, cQuote ) )
+ {
+ rString.Erase( rString.Len() - 1 ).Erase( 0, 1 );
+ if (bUnescapeEmbedded)
+ {
+ sal_Unicode pQ[3];
+ pQ[0] = pQ[1] = cQuote;
+ pQ[2] = 0;
+ String aQuotes( pQ );
+ rString.SearchAndReplaceAll( aQuotes, cQuote);
+ }
+ }
+}
+
+xub_StrLen ScGlobal::FindUnquoted( const String& rString, sal_Unicode cChar, xub_StrLen nStart, sal_Unicode cQuote )
+{
+ const sal_Unicode* const pStart = rString.GetBuffer();
+ const sal_Unicode* const pStop = pStart + rString.Len();
+ const sal_Unicode* p = pStart + nStart;
+ bool bQuoted = false;
+ while (p < pStop)
+ {
+ if (*p == cChar && !bQuoted)
+ return sal::static_int_cast< xub_StrLen >( p - pStart );
+ else if (*p == cQuote)
+ {
+ if (!bQuoted)
+ bQuoted = true;
+ else if (p < pStop-1 && *(p+1) == cQuote)
+ ++p;
+ else
+ bQuoted = false;
+ }
+ ++p;
+ }
+ return STRING_NOTFOUND;
+}
+
+const sal_Unicode* ScGlobal::FindUnquoted( const sal_Unicode* pString, sal_Unicode cChar, sal_Unicode cQuote )
+{
+ const sal_Unicode* p = pString;
+ bool bQuoted = false;
+ while (*p)
+ {
+ if (*p == cChar && !bQuoted)
+ return p;
+ else if (*p == cQuote)
+ {
+ if (!bQuoted)
+ bQuoted = true;
+ else if (*(p+1) == cQuote)
+ ++p;
+ else
+ bQuoted = false;
+ }
+ ++p;
+ }
+ return NULL;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScGlobal::EETextObjEqual( const EditTextObject* pObj1,
+ const EditTextObject* pObj2 )
+{
+ if ( pObj1 == pObj2 ) // both empty or the same object
+ return TRUE;
+
+ if ( pObj1 && pObj2 )
+ {
+ // first test for equal text content
+ USHORT nParCount = pObj1->GetParagraphCount();
+ if ( nParCount != pObj2->GetParagraphCount() )
+ return FALSE;
+ for (USHORT nPar=0; nPar<nParCount; nPar++)
+ if ( pObj1->GetText(nPar) != pObj2->GetText(nPar) )
+ return FALSE;
+
+ SvMemoryStream aStream1;
+ SvMemoryStream aStream2;
+ pObj1->Store( aStream1 );
+ pObj2->Store( aStream2 );
+ ULONG nSize = aStream1.Tell();
+ if ( aStream2.Tell() == nSize )
+ if ( !memcmp( aStream1.GetData(), aStream2.GetData(), (USHORT) nSize ) )
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void ScGlobal::OpenURL( const String& rURL, const String& rTarget )
+{
+ // OpenURL wird immer ueber irgendwelche Umwege durch Mausklicks im GridWindow
+ // aufgerufen, darum stimmen pScActiveViewShell und nScClickMouseModifier.
+
+ SfxStringItem aUrl( SID_FILE_NAME, rURL );
+ SfxStringItem aTarget( SID_TARGETNAME, rTarget );
+
+ if ( nScClickMouseModifier & KEY_MOD1 ) // control-click -> into new window
+ aTarget.SetValue(
+ String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("_blank")) );
+
+ SfxViewFrame* pFrame = NULL;
+ String aReferName;
+ if ( pScActiveViewShell )
+ {
+ pFrame = pScActiveViewShell->GetViewFrame();
+ SfxMedium* pMed = pFrame->GetObjectShell()->GetMedium();
+ if (pMed)
+ aReferName = pMed->GetName();
+ }
+
+ SfxFrameItem aFrm( SID_DOCFRAME, pFrame );
+ SfxStringItem aReferer( SID_REFERER, aReferName );
+
+ SfxBoolItem aNewView( SID_OPEN_NEW_VIEW, FALSE );
+ SfxBoolItem aBrowsing( SID_BROWSE, TRUE );
+
+ // kein SID_SILENT mehr wegen Bug #42525# (war angeblich sowieso falsch)
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ pViewFrm->GetDispatcher()->Execute( SID_OPENDOC,
+ SFX_CALLMODE_ASYNCHRON | SFX_CALLMODE_RECORD,
+ &aUrl, &aTarget,
+ &aFrm, &aReferer,
+ &aNewView, &aBrowsing,
+ 0L );
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScGlobal::IsSystemRTL()
+{
+ return MsLangId::isRightToLeft( Application::GetSettings().GetLanguage() );
+}
+
+BYTE ScGlobal::GetDefaultScriptType()
+{
+ // Used when text contains only WEAK characters.
+ // Script type of office language is used then (same as GetEditDefaultLanguage,
+ // to get consistent behavior of text in simple cells and EditEngine,
+ // also same as GetAppLanguage() in Writer)
+
+ return (BYTE) SvtLanguageOptions::GetScriptTypeOfLanguage( Application::GetSettings().GetLanguage() );
+}
+
+LanguageType ScGlobal::GetEditDefaultLanguage()
+{
+ // used for EditEngine::SetDefaultLanguage
+
+ return Application::GetSettings().GetLanguage();
+}
+
+USHORT ScGlobal::GetScriptedWhichID( BYTE nScriptType, USHORT nWhich )
+{
+ switch ( nScriptType )
+ {
+ case SCRIPTTYPE_LATIN:
+ case SCRIPTTYPE_ASIAN:
+ case SCRIPTTYPE_COMPLEX:
+ break; // take exact matches
+ default: // prefer one, first COMPLEX, then ASIAN
+ if ( nScriptType & SCRIPTTYPE_COMPLEX )
+ nScriptType = SCRIPTTYPE_COMPLEX;
+ else if ( nScriptType & SCRIPTTYPE_ASIAN )
+ nScriptType = SCRIPTTYPE_ASIAN;
+ }
+ switch ( nScriptType )
+ {
+ case SCRIPTTYPE_COMPLEX:
+ {
+ switch ( nWhich )
+ {
+ case ATTR_FONT:
+ case ATTR_CJK_FONT:
+ nWhich = ATTR_CTL_FONT;
+ break;
+ case ATTR_FONT_HEIGHT:
+ case ATTR_CJK_FONT_HEIGHT:
+ nWhich = ATTR_CTL_FONT_HEIGHT;
+ break;
+ case ATTR_FONT_WEIGHT:
+ case ATTR_CJK_FONT_WEIGHT:
+ nWhich = ATTR_CTL_FONT_WEIGHT;
+ break;
+ case ATTR_FONT_POSTURE:
+ case ATTR_CJK_FONT_POSTURE:
+ nWhich = ATTR_CTL_FONT_POSTURE;
+ break;
+ }
+ }
+ break;
+ case SCRIPTTYPE_ASIAN:
+ {
+ switch ( nWhich )
+ {
+ case ATTR_FONT:
+ case ATTR_CTL_FONT:
+ nWhich = ATTR_CJK_FONT;
+ break;
+ case ATTR_FONT_HEIGHT:
+ case ATTR_CTL_FONT_HEIGHT:
+ nWhich = ATTR_CJK_FONT_HEIGHT;
+ break;
+ case ATTR_FONT_WEIGHT:
+ case ATTR_CTL_FONT_WEIGHT:
+ nWhich = ATTR_CJK_FONT_WEIGHT;
+ break;
+ case ATTR_FONT_POSTURE:
+ case ATTR_CTL_FONT_POSTURE:
+ nWhich = ATTR_CJK_FONT_POSTURE;
+ break;
+ }
+ }
+ break;
+ default:
+ {
+ switch ( nWhich )
+ {
+ case ATTR_CTL_FONT:
+ case ATTR_CJK_FONT:
+ nWhich = ATTR_FONT;
+ break;
+ case ATTR_CTL_FONT_HEIGHT:
+ case ATTR_CJK_FONT_HEIGHT:
+ nWhich = ATTR_FONT_HEIGHT;
+ break;
+ case ATTR_CTL_FONT_WEIGHT:
+ case ATTR_CJK_FONT_WEIGHT:
+ nWhich = ATTR_FONT_WEIGHT;
+ break;
+ case ATTR_CTL_FONT_POSTURE:
+ case ATTR_CJK_FONT_POSTURE:
+ nWhich = ATTR_FONT_POSTURE;
+ break;
+ }
+ }
+ }
+ return nWhich;
+}
+
+//------------------------------------------------------------------------
+
+void ScGlobal::AddLanguage( SfxItemSet& rSet, SvNumberFormatter& rFormatter )
+{
+ DBG_ASSERT( rSet.GetItemState( ATTR_LANGUAGE_FORMAT, FALSE ) == SFX_ITEM_DEFAULT,
+ "ScGlobal::AddLanguage - language already added");
+
+ const SfxPoolItem* pHardItem;
+ if ( rSet.GetItemState( ATTR_VALUE_FORMAT, FALSE, &pHardItem ) == SFX_ITEM_SET )
+ {
+ const SvNumberformat* pHardFormat = rFormatter.GetEntry(
+ ((const SfxUInt32Item*)pHardItem)->GetValue() );
+
+ ULONG nParentFmt = 0; // pool default
+ const SfxItemSet* pParent = rSet.GetParent();
+ if ( pParent )
+ nParentFmt = ((const SfxUInt32Item&)pParent->Get( ATTR_VALUE_FORMAT )).GetValue();
+ const SvNumberformat* pParFormat = rFormatter.GetEntry( nParentFmt );
+
+ if ( pHardFormat && pParFormat &&
+ (pHardFormat->GetLanguage() != pParFormat->GetLanguage()) )
+ rSet.Put( SvxLanguageItem( pHardFormat->GetLanguage(), ATTR_LANGUAGE_FORMAT ) );
+ }
+}
+
+
+
+
+
+//===================================================================
+// class ScFunctionList:
+//===================================================================
+
+//===================================================================
+// class ScFuncRes
+// fuer temporaere Objekte zum Holen der Resourcen
+
+class ScFuncRes : public Resource
+{
+public:
+ ScFuncRes( ResId&, ScFuncDesc*, bool & rbSuppressed );
+
+private:
+ USHORT GetNum();
+};
+
+//--------------------------------------------------------------------
+
+ScFuncRes::ScFuncRes( ResId &aRes, ScFuncDesc* pDesc, bool & rbSuppressed )
+ : Resource(aRes)
+{
+ rbSuppressed = (bool)GetNum();
+ pDesc->nCategory = GetNum();
+ pDesc->nHelpId = GetNum() + 32768; //! Hack, see scfuncs.src
+ pDesc->nArgCount = GetNum();
+ USHORT nArgs = pDesc->nArgCount;
+ if (nArgs >= VAR_ARGS)
+ nArgs -= VAR_ARGS - 1;
+ if (nArgs)
+ {
+ pDesc->pDefArgFlags = new ScFuncDesc::ParameterFlags[nArgs];
+ for (USHORT i = 0; i < nArgs; i++)
+ {
+ pDesc->pDefArgFlags[i].bOptional = (bool)GetNum();
+ }
+ }
+ // Need to read the value from the resource even if nArgs==0 to advance the
+ // resource position pointer, so this can't be in the if(nArgs) block above.
+ USHORT nSuppressed = GetNum();
+ if (nSuppressed)
+ {
+ if (nSuppressed > nArgs)
+ {
+ DBG_ERROR3( "ScFuncRes: suppressed parameters count mismatch on OpCode %u: suppressed %d > params %d",
+ aRes.GetId(), (int)nSuppressed, (int)nArgs);
+ nSuppressed = nArgs; // sanitize
+ }
+ for (USHORT i=0; i < nSuppressed; ++i)
+ {
+ USHORT nParam = GetNum();
+ if (nParam < nArgs)
+ {
+ if (pDesc->nArgCount >= VAR_ARGS && nParam == nArgs-1)
+ {
+ DBG_ERROR3( "ScFuncRes: VAR_ARGS parameters can't be suppressed, on OpCode %u: param %d == arg %d-1",
+ aRes.GetId(), (int)nParam, (int)nArgs);
+ }
+ else
+ {
+ pDesc->pDefArgFlags[nParam].bSuppress = true;
+ pDesc->bHasSuppressedArgs = true;
+ }
+ }
+ else
+ {
+ DBG_ERROR3( "ScFuncRes: suppressed parameter exceeds count on OpCode %u: param %d >= args %d",
+ aRes.GetId(), (int)nParam, (int)nArgs);
+ }
+ }
+ }
+
+ pDesc->pFuncName = new String( ScCompiler::GetNativeSymbol( static_cast<OpCode>( aRes.GetId())));
+ pDesc->pFuncDesc = new String(ScResId(1));
+
+ if (nArgs)
+ {
+ pDesc->ppDefArgNames = new String*[nArgs];
+ pDesc->ppDefArgDescs = new String*[nArgs];
+ for (USHORT i = 0; i < nArgs; i++)
+ {
+ pDesc->ppDefArgNames[i] = new String(ScResId(2*(i+1) ));
+ pDesc->ppDefArgDescs[i] = new String(ScResId(2*(i+1)+1));
+ }
+ }
+
+ FreeResource();
+}
+
+//------------------------------------------------------------------------
+
+USHORT ScFuncRes::GetNum()
+{
+ return ReadShortRes();
+}
+
+//=========================================================================
+
+// um an die protected von Resource ranzukommen
+class ScResourcePublisher : public Resource
+{
+private:
+ void FreeResource() { Resource::FreeResource(); }
+public:
+ ScResourcePublisher( const ScResId& rId ) : Resource( rId ) {}
+ ~ScResourcePublisher() { FreeResource(); }
+ BOOL IsAvailableRes( const ResId& rId ) const
+ { return Resource::IsAvailableRes( rId ); }
+
+};
+
+
+ScFunctionList::ScFunctionList() :
+ nMaxFuncNameLen ( 0 )
+{
+ ScFuncDesc* pDesc = NULL;
+ xub_StrLen nStrLen = 0;
+ FuncCollection* pFuncColl;
+ USHORT i,j;
+ USHORT nDescBlock[] =
+ {
+ RID_SC_FUNCTION_DESCRIPTIONS1,
+ RID_SC_FUNCTION_DESCRIPTIONS2
+ };
+ const USHORT nBlocks = sizeof(nDescBlock) / sizeof(USHORT);
+
+ aFunctionList.Clear();
+
+ for ( USHORT k = 0; k < nBlocks; k++ )
+ {
+ ::std::auto_ptr<ScResourcePublisher> pBlock( new ScResourcePublisher( ScResId( nDescBlock[k] ) ) );
+ // Browse for all possible OpCodes. This is not the fastest method, but
+ // otherwise the sub resources within the resource blocks and the
+ // resource blocks themselfs would had to be ordered according to
+ // OpCodes, which is utopian..
+ for (i = 0; i <= SC_OPCODE_LAST_OPCODE_ID; i++)
+ {
+ ScResId aRes(i);
+ aRes.SetRT(RSC_RESOURCE);
+ // Sub resource of OpCode available?
+ if (pBlock->IsAvailableRes(aRes))
+ {
+ pDesc = new ScFuncDesc;
+ bool bSuppressed = false;
+ ScFuncRes aSubRes( aRes, pDesc, bSuppressed);
+ // Instead of dealing with this exceptional case at 1001 places
+ // we simply don't add an entirely suppressed function to the
+ // list and delete it.
+ if (bSuppressed)
+ delete pDesc;
+ else
+ {
+ pDesc->nFIndex = i;
+ aFunctionList.Insert( pDesc, LIST_APPEND );
+
+ nStrLen = (*(pDesc->pFuncName)).Len();
+ if (nStrLen > nMaxFuncNameLen)
+ nMaxFuncNameLen = nStrLen;
+ }
+ }
+ }
+ }
+
+ USHORT nNextId = SC_OPCODE_LAST_OPCODE_ID + 1; // FuncID for AddIn functions
+
+ // Auswertung AddIn-Liste
+ String aDefArgNameValue(RTL_CONSTASCII_STRINGPARAM("value"));
+ String aDefArgNameString(RTL_CONSTASCII_STRINGPARAM("string"));
+ String aDefArgNameValues(RTL_CONSTASCII_STRINGPARAM("values"));
+ String aDefArgNameStrings(RTL_CONSTASCII_STRINGPARAM("strings"));
+ String aDefArgNameCells(RTL_CONSTASCII_STRINGPARAM("cells"));
+ String aDefArgNameNone(RTL_CONSTASCII_STRINGPARAM("none"));
+ String aDefArgDescValue(RTL_CONSTASCII_STRINGPARAM("a value"));
+ String aDefArgDescString(RTL_CONSTASCII_STRINGPARAM("a string"));
+ String aDefArgDescValues(RTL_CONSTASCII_STRINGPARAM("array of values"));
+ String aDefArgDescStrings(RTL_CONSTASCII_STRINGPARAM("array of strings"));
+ String aDefArgDescCells(RTL_CONSTASCII_STRINGPARAM("range of cells"));
+ String aDefArgDescNone(RTL_CONSTASCII_STRINGPARAM("none"));
+ String aArgName, aArgDesc;
+ pFuncColl = ScGlobal::GetFuncCollection();
+ for (i = 0; i < pFuncColl->GetCount(); i++)
+ {
+ pDesc = new ScFuncDesc;
+ FuncData *pAddInFuncData = (FuncData*)pFuncColl->At(i);
+ USHORT nArgs = pAddInFuncData->GetParamCount() - 1;
+ pAddInFuncData->GetParamDesc( aArgName, aArgDesc, 0 );
+ pDesc->nFIndex = nNextId++; // ??? OpCode vergeben
+ pDesc->nCategory = ID_FUNCTION_GRP_ADDINS;
+ pDesc->pFuncName = new String(pAddInFuncData->GetInternalName());
+ pDesc->pFuncName->ToUpperAscii();
+ pDesc->pFuncDesc = new String( aArgDesc );
+ *(pDesc->pFuncDesc) += '\n';
+ pDesc->pFuncDesc->AppendAscii(RTL_CONSTASCII_STRINGPARAM( "( AddIn: " ));
+ *(pDesc->pFuncDesc) += pAddInFuncData->GetModuleName();
+ pDesc->pFuncDesc->AppendAscii(RTL_CONSTASCII_STRINGPARAM( " )" ));
+ pDesc->nArgCount = nArgs;
+ if (nArgs)
+ {
+ pDesc->pDefArgFlags = new ScFuncDesc::ParameterFlags[nArgs];
+ pDesc->ppDefArgNames = new String*[nArgs];
+ pDesc->ppDefArgDescs = new String*[nArgs];
+ for (j = 0; j < nArgs; j++)
+ {
+ pDesc->pDefArgFlags[j].bOptional = false;
+ pDesc->pDefArgFlags[j].bSuppress = false;
+ pAddInFuncData->GetParamDesc( aArgName, aArgDesc, j+1 );
+ if ( aArgName.Len() )
+ pDesc->ppDefArgNames[j] = new String( aArgName );
+ else
+ {
+ switch (pAddInFuncData->GetParamType(j+1))
+ {
+ case PTR_DOUBLE:
+ pDesc->ppDefArgNames[j] = new String( aDefArgNameValue );
+ break;
+ case PTR_STRING:
+ pDesc->ppDefArgNames[j] = new String( aDefArgNameString );
+ break;
+ case PTR_DOUBLE_ARR:
+ pDesc->ppDefArgNames[j] = new String( aDefArgNameValues );
+ break;
+ case PTR_STRING_ARR:
+ pDesc->ppDefArgNames[j] = new String( aDefArgNameStrings );
+ break;
+ case PTR_CELL_ARR:
+ pDesc->ppDefArgNames[j] = new String( aDefArgNameCells );
+ break;
+ default:
+ pDesc->ppDefArgNames[j] = new String( aDefArgNameNone );
+ break;
+ }
+ }
+ if ( aArgDesc.Len() )
+ pDesc->ppDefArgDescs[j] = new String( aArgDesc );
+ else
+ {
+ switch (pAddInFuncData->GetParamType(j+1))
+ {
+ case PTR_DOUBLE:
+ pDesc->ppDefArgDescs[j] = new String( aDefArgDescValue );
+ break;
+ case PTR_STRING:
+ pDesc->ppDefArgDescs[j] = new String( aDefArgDescString );
+ break;
+ case PTR_DOUBLE_ARR:
+ pDesc->ppDefArgDescs[j] = new String( aDefArgDescValues );
+ break;
+ case PTR_STRING_ARR:
+ pDesc->ppDefArgDescs[j] = new String( aDefArgDescStrings );
+ break;
+ case PTR_CELL_ARR:
+ pDesc->ppDefArgDescs[j] = new String( aDefArgDescCells );
+ break;
+ default:
+ pDesc->ppDefArgDescs[j] = new String( aDefArgDescNone );
+ break;
+ }
+ }
+ }
+ }
+// pDesc->nHelpId = 0;
+
+ aFunctionList.Insert(pDesc, LIST_APPEND);
+ nStrLen = (*(pDesc->pFuncName)).Len();
+ if ( nStrLen > nMaxFuncNameLen)
+ nMaxFuncNameLen = nStrLen;
+ }
+
+ // StarOne AddIns
+
+ ScUnoAddInCollection* pUnoAddIns = ScGlobal::GetAddInCollection();
+ long nUnoCount = pUnoAddIns->GetFuncCount();
+ for (long nFunc=0; nFunc<nUnoCount; nFunc++)
+ {
+ pDesc = new ScFuncDesc;
+ pDesc->nFIndex = nNextId++;
+
+ if ( pUnoAddIns->FillFunctionDesc( nFunc, *pDesc ) )
+ {
+ aFunctionList.Insert(pDesc, LIST_APPEND);
+ nStrLen = (*(pDesc->pFuncName)).Len();
+ if (nStrLen > nMaxFuncNameLen)
+ nMaxFuncNameLen = nStrLen;
+ }
+ else
+ delete pDesc;
+ }
+}
+
+//------------------------------------------------------------------------
+
+ScFunctionList::~ScFunctionList()
+{
+ const ScFuncDesc* pDesc = First();
+ while (pDesc)
+ {
+ delete pDesc;
+ pDesc = Next();
+ }
+}
+
+
+//========================================================================
+// class ScFuncDesc:
+
+ScFuncDesc::ScFuncDesc() :
+ pFuncName (NULL),
+ pFuncDesc (NULL),
+ ppDefArgNames (NULL),
+ ppDefArgDescs (NULL),
+ pDefArgFlags (NULL),
+ nFIndex (0),
+ nCategory (0),
+ nArgCount (0),
+ nHelpId (0),
+ bIncomplete (false),
+ bHasSuppressedArgs(false)
+{}
+
+//------------------------------------------------------------------------
+
+ScFuncDesc::~ScFuncDesc()
+{
+ Clear();
+}
+
+//------------------------------------------------------------------------
+
+void ScFuncDesc::Clear()
+{
+ USHORT nArgs = nArgCount;
+ if (nArgs >= VAR_ARGS) nArgs -= VAR_ARGS-1;
+ if (nArgs)
+ {
+ for (USHORT i=0; i<nArgs; i++ )
+ {
+ delete ppDefArgNames[i];
+ delete ppDefArgDescs[i];
+ }
+ delete [] ppDefArgNames;
+ delete [] ppDefArgDescs;
+ delete [] pDefArgFlags;
+ }
+ nArgCount = 0;
+ ppDefArgNames = NULL;
+ ppDefArgDescs = NULL;
+ pDefArgFlags = NULL;
+
+ delete pFuncName;
+ pFuncName = NULL;
+
+ delete pFuncDesc;
+ pFuncDesc = NULL;
+
+ nFIndex = 0;
+ nCategory = 0;
+ nHelpId = 0;
+ bIncomplete = false;
+ bHasSuppressedArgs = false;
+}
+
+//------------------------------------------------------------------------
+
+String ScFuncDesc::GetParamList() const
+{
+ const String& sep = ScCompiler::GetNativeSymbol(ocSep);
+
+ String aSig;
+
+ if ( nArgCount > 0 )
+ {
+ if ( nArgCount < VAR_ARGS )
+ {
+ USHORT nLastSuppressed = nArgCount;
+ USHORT nLastAdded = nArgCount;
+ for ( USHORT i=0; i<nArgCount; i++ )
+ {
+ if (pDefArgFlags[i].bSuppress)
+ nLastSuppressed = i;
+ else
+ {
+ nLastAdded = i;
+ aSig += *(ppDefArgNames[i]);
+ if ( i != nArgCount-1 )
+ {
+ aSig.Append(sep);
+ aSig.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " " ));
+ }
+ }
+ }
+ // If only suppressed parameters follow the last added parameter,
+ // remove one "; "
+ if (nLastSuppressed < nArgCount && nLastAdded < nLastSuppressed &&
+ aSig.Len() >= 2)
+ aSig.Erase( aSig.Len() - 2 );
+ }
+ else
+ {
+ USHORT nFix = nArgCount - VAR_ARGS;
+ for ( USHORT nArg = 0; nArg < nFix; nArg++ )
+ {
+ if (!pDefArgFlags[nArg].bSuppress)
+ {
+ aSig += *(ppDefArgNames[nArg]);
+ aSig.Append(sep);
+ aSig.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " " ));
+ }
+ }
+ /* NOTE: Currently there are no suppressed var args parameters. If
+ * there were, we'd have to cope with it here and above for the fix
+ * parameters. For now parameters are always added, so no special
+ * treatment of a trailing "; " necessary. */
+ aSig += *(ppDefArgNames[nFix]);
+ aSig += '1';
+ aSig.Append(sep);
+ aSig.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " " ));
+ aSig += *(ppDefArgNames[nFix]);
+ aSig += '2';
+ aSig.Append(sep);
+ aSig.AppendAscii(RTL_CONSTASCII_STRINGPARAM( " ... " ));
+ }
+ }
+
+ return aSig;
+}
+
+//------------------------------------------------------------------------
+
+String ScFuncDesc::GetSignature() const
+{
+ String aSig;
+
+ if(pFuncName)
+ {
+ aSig = *pFuncName;
+
+ String aParamList( GetParamList() );
+ if( aParamList.Len() )
+ {
+ aSig.AppendAscii(RTL_CONSTASCII_STRINGPARAM( "( " ));
+ aSig.Append( aParamList );
+ // U+00A0 (NBSP) prevents automatic line break
+ aSig.Append( static_cast< sal_Unicode >(0xA0) ).Append( ')' );
+ }
+ else
+ aSig.AppendAscii(RTL_CONSTASCII_STRINGPARAM( "()" ));
+ }
+ return aSig;
+}
+
+//------------------------------------------------------------------------
+
+::rtl::OUString ScFuncDesc::getFormula( const ::std::vector< ::rtl::OUString >& _aArguments ) const
+{
+ const String& sep = ScCompiler::GetNativeSymbol(ocSep);
+
+ ::rtl::OUStringBuffer aFormula;
+
+ if(pFuncName)
+ {
+ aFormula.append( *pFuncName );
+
+ aFormula.appendAscii( "(" );
+ ::std::vector< ::rtl::OUString >::const_iterator aIter = _aArguments.begin();
+ ::std::vector< ::rtl::OUString >::const_iterator aEnd = _aArguments.end();
+
+ if ( nArgCount > 0 && aIter != aEnd )
+ {
+ BOOL bLastArg = ( aIter->getLength() == 0 );
+
+ while( aIter != aEnd && !bLastArg )
+ {
+ aFormula.append( *(aIter) );
+ if ( aIter != (aEnd-1) )
+ {
+ bLastArg = !( (aIter+1)->getLength() > 0 );
+ if ( !bLastArg )
+ aFormula.append( sep );
+ }
+
+ ++aIter;
+ }
+ }
+
+ aFormula.appendAscii( ")" );
+ }
+ return aFormula.makeStringAndClear();
+}
+
+//------------------------------------------------------------------------
+
+USHORT ScFuncDesc::GetSuppressedArgCount() const
+{
+ if (!bHasSuppressedArgs || !pDefArgFlags)
+ return nArgCount;
+
+ USHORT nArgs = nArgCount;
+ if (nArgs >= VAR_ARGS)
+ nArgs -= VAR_ARGS - 1;
+ USHORT nCount = nArgs;
+ for (USHORT i=0; i < nArgs; ++i)
+ {
+ if (pDefArgFlags[i].bSuppress)
+ --nCount;
+ }
+ if (nArgCount >= VAR_ARGS)
+ nCount += VAR_ARGS - 1;
+ return nCount;
+}
+
+//------------------------------------------------------------------------
+
+::rtl::OUString ScFuncDesc::getFunctionName() const
+{
+ ::rtl::OUString sRet;
+ if ( pFuncName )
+ sRet = *pFuncName;
+ return sRet;
+}
+// -----------------------------------------------------------------------------
+const formula::IFunctionCategory* ScFuncDesc::getCategory() const
+{
+ return ScGlobal::GetStarCalcFunctionMgr()->getCategory(nCategory);
+}
+// -----------------------------------------------------------------------------
+::rtl::OUString ScFuncDesc::getDescription() const
+{
+ ::rtl::OUString sRet;
+ if ( pFuncDesc )
+ sRet = *pFuncDesc;
+ return sRet;
+}
+// -----------------------------------------------------------------------------
+// GetSuppressedArgCount
+xub_StrLen ScFuncDesc::getSuppressedArgumentCount() const
+{
+ return GetSuppressedArgCount();
+}
+// -----------------------------------------------------------------------------
+//
+void ScFuncDesc::fillVisibleArgumentMapping(::std::vector<USHORT>& _rArguments) const
+{
+ if (!bHasSuppressedArgs || !pDefArgFlags)
+ {
+ _rArguments.resize( nArgCount);
+ ::std::iota( _rArguments.begin(), _rArguments.end(), 0);
+ }
+
+ _rArguments.reserve( nArgCount);
+ USHORT nArgs = nArgCount;
+ if (nArgs >= VAR_ARGS)
+ nArgs -= VAR_ARGS - 1;
+ for (USHORT i=0; i < nArgs; ++i)
+ {
+ if (!pDefArgFlags[i].bSuppress)
+ _rArguments.push_back(i);
+ }
+}
+// -----------------------------------------------------------------------------
+void ScFuncDesc::initArgumentInfo() const
+{
+ // get the full argument description
+ // (add-in has to be instantiated to get the type information)
+
+ if ( bIncomplete && pFuncName )
+ {
+ ScUnoAddInCollection& rAddIns = *ScGlobal::GetAddInCollection();
+ String aIntName = rAddIns.FindFunction( *pFuncName, TRUE ); // pFuncName is upper-case
+
+ if ( aIntName.Len() )
+ {
+ // GetFuncData with bComplete=true loads the component and updates
+ // the global function list if needed.
+
+ rAddIns.GetFuncData( aIntName, true );
+ }
+
+ if ( bIncomplete )
+ {
+ DBG_ERRORFILE( "couldn't initialize add-in function" );
+ const_cast<ScFuncDesc*>(this)->bIncomplete = FALSE; // even if there was an error, don't try again
+ }
+ }
+}
+// -----------------------------------------------------------------------------
+::rtl::OUString ScFuncDesc::getSignature() const
+{
+ return GetSignature();
+}
+// -----------------------------------------------------------------------------
+long ScFuncDesc::getHelpId() const
+{
+ return nHelpId;
+}
+// -----------------------------------------------------------------------------
+
+// parameter
+sal_uInt32 ScFuncDesc::getParameterCount() const
+{
+ return nArgCount;
+}
+// -----------------------------------------------------------------------------
+::rtl::OUString ScFuncDesc::getParameterName(sal_uInt32 _nPos) const
+{
+ return *(ppDefArgNames[_nPos]);
+}
+// -----------------------------------------------------------------------------
+::rtl::OUString ScFuncDesc::getParameterDescription(sal_uInt32 _nPos) const
+{
+ return *(ppDefArgDescs[_nPos]);
+}
+// -----------------------------------------------------------------------------
+bool ScFuncDesc::isParameterOptional(sal_uInt32 _nPos) const
+{
+ return pDefArgFlags[_nPos].bOptional;
+}
+// -----------------------------------------------------------------------------
+//========================================================================
+// class ScFunctionMgr:
+
+ScFunctionMgr::ScFunctionMgr()
+ : pFuncList ( ScGlobal::GetStarCalcFunctionList() ),
+ pCurCatList ( NULL )
+{
+ DBG_ASSERT( pFuncList, "Funktionsliste nicht gefunden." );
+ ULONG nCount = pFuncList->GetCount();
+ const ScFuncDesc* pDesc;
+ List* pRootList;
+ ULONG n;
+
+ for ( USHORT i=0; i<MAX_FUNCCAT; i++ ) // Kategorie-Listen erstellen
+ aCatLists[i] = new List;
+
+ pRootList = aCatLists[0]; // Gesamtliste ("Alle") erstellen
+ for ( n=0; n<nCount; n++ )
+ {
+ ULONG nTmpCnt=0;
+ pDesc = pFuncList->GetFunction(n);
+ for (nTmpCnt = 0; nTmpCnt < n; nTmpCnt++)
+ {
+ // ist zwar case-sensitiv, aber Umlaute muessen richtig einsortiert werden
+
+ const ScFuncDesc* pTmpDesc = (const ScFuncDesc*)pRootList->GetObject(nTmpCnt);
+ if ( ScGlobal::pCaseCollator->compareString(
+ *pDesc->pFuncName, *pTmpDesc->pFuncName ) == COMPARE_LESS )
+ break;
+ }
+ pRootList->Insert((void*)pDesc, nTmpCnt); // Einsortieren
+ }
+
+ for ( n=0; n<nCount; n++ ) // in Gruppenlisten kopieren
+ {
+ pDesc = (const ScFuncDesc*)pRootList->GetObject(n);
+ DBG_ASSERT((pDesc->nCategory) < MAX_FUNCCAT, "Unbekannte Kategorie");
+ if ((pDesc->nCategory) < MAX_FUNCCAT)
+ aCatLists[pDesc->nCategory]->Insert((void*)pDesc, LIST_APPEND);
+ }
+}
+
+//------------------------------------------------------------------------
+
+ScFunctionMgr::~ScFunctionMgr()
+{
+ for (USHORT i = 0; i < MAX_FUNCCAT; i++)
+ delete aCatLists[i];
+// delete pFuncList; // Macht spaeter die App
+}
+
+//------------------------------------------------------------------------
+
+const ScFuncDesc* ScFunctionMgr::Get( const String& rFName ) const
+{
+ const ScFuncDesc* pDesc = NULL;
+ if (rFName.Len() <= pFuncList->GetMaxFuncNameLen())
+ for (pDesc = First(0); pDesc; pDesc = Next())
+ if (rFName.EqualsIgnoreCaseAscii(*(pDesc->pFuncName)))
+ break;
+ return pDesc;
+}
+
+//------------------------------------------------------------------------
+
+const ScFuncDesc* ScFunctionMgr::Get( USHORT nFIndex ) const
+{
+ const ScFuncDesc* pDesc;
+ for (pDesc = First(0); pDesc; pDesc = Next())
+ if (pDesc->nFIndex == nFIndex)
+ break;
+ return pDesc;
+}
+
+//------------------------------------------------------------------------
+
+const ScFuncDesc* ScFunctionMgr::First( USHORT nCategory ) const
+{
+ DBG_ASSERT( nCategory < MAX_FUNCCAT, "Unbekannte Kategorie" );
+
+ if ( nCategory < MAX_FUNCCAT )
+ {
+ pCurCatList = aCatLists[nCategory];
+ return (const ScFuncDesc*)pCurCatList->First();
+ }
+ else
+ {
+ pCurCatList = NULL;
+ return NULL;
+ }
+}
+
+//------------------------------------------------------------------------
+
+const ScFuncDesc* ScFunctionMgr::Next() const
+{
+ if ( pCurCatList )
+ return (const ScFuncDesc*)pCurCatList->Next();
+ else
+ return NULL;
+}
+sal_uInt32 ScFunctionMgr::getCount() const
+{
+ return MAX_FUNCCAT - 1;
+}
+const formula::IFunctionCategory* ScFunctionMgr::getCategory(sal_uInt32 nCategory) const
+{
+ formula::IFunctionCategory* pRet = NULL;
+ if ( nCategory < (MAX_FUNCCAT-1) )
+ {
+ pRet = new ScFunctionCategory(const_cast<ScFunctionMgr*>(this),aCatLists[nCategory+1],nCategory); // aCatLists[0] is "all"
+ }
+ return pRet;
+}
+// -----------------------------------------------------------------------------
+const formula::IFunctionDescription* ScFunctionMgr::getFunctionByName(const ::rtl::OUString& _sFunctionName) const
+{
+ return Get(_sFunctionName);
+}
+// -----------------------------------------------------------------------------
+void ScFunctionMgr::fillLastRecentlyUsedFunctions(::std::vector< const formula::IFunctionDescription*>& _rLastRUFunctions) const
+{
+#define LRU_MAX 10
+
+ const ScAppOptions& rAppOpt = SC_MOD()->GetAppOptions();
+ USHORT nLRUFuncCount = Min( rAppOpt.GetLRUFuncListCount(), (USHORT)LRU_MAX );
+ USHORT* pLRUListIds = rAppOpt.GetLRUFuncList();
+
+ if ( pLRUListIds )
+ {
+ for ( USHORT i=0; i<nLRUFuncCount; i++ )
+ _rLastRUFunctions.push_back( Get( pLRUListIds[i] ) );
+ }
+}
+// -----------------------------------------------------------------------------
+String ScFunctionMgr::GetCategoryName(sal_uInt32 _nCategoryNumber )
+{
+ if ( _nCategoryNumber > SC_FUNCGROUP_COUNT )
+ {
+ DBG_ERROR("Invalid category number!");
+ return String();
+ } // if ( _nCategoryNumber >= SC_FUNCGROUP_COUNT )
+
+ ::std::auto_ptr<ScResourcePublisher> pCategories( new ScResourcePublisher( ScResId( RID_FUNCTION_CATEGORIES ) ) );
+ return String(ScResId((USHORT)_nCategoryNumber));
+}
+sal_Unicode ScFunctionMgr::getSingleToken(const formula::IFunctionManager::EToken _eToken) const
+{
+ switch(_eToken)
+ {
+ case eOk:
+ return ScCompiler::GetNativeSymbol(ocOpen).GetChar(0);
+ case eClose:
+ return ScCompiler::GetNativeSymbol(ocClose).GetChar(0);
+ case eSep:
+ return ScCompiler::GetNativeSymbol(ocSep).GetChar(0);
+ case eArrayOpen:
+ return ScCompiler::GetNativeSymbol(ocArrayOpen).GetChar(0);
+ case eArrayClose:
+ return ScCompiler::GetNativeSymbol(ocArrayClose).GetChar(0);
+ } // switch(_eToken)
+ return 0;
+}
+// -----------------------------------------------------------------------------
+sal_uInt32 ScFunctionCategory::getCount() const
+{
+ return m_pCategory->Count();
+}
+// -----------------------------------------------------------------------------
+const formula::IFunctionManager* ScFunctionCategory::getFunctionManager() const
+{
+ return m_pMgr;
+}
+// -----------------------------------------------------------------------------
+::rtl::OUString ScFunctionCategory::getName() const
+{
+ if ( !m_sName.getLength() )
+ m_sName = ScFunctionMgr::GetCategoryName(m_nCategory+1);
+ return m_sName;
+}
+// -----------------------------------------------------------------------------
+const formula::IFunctionDescription* ScFunctionCategory::getFunction(sal_uInt32 _nPos) const
+{
+ const ScFuncDesc* pDesc = NULL;
+ sal_uInt32 i = 0;
+ for (pDesc = (const ScFuncDesc*)m_pCategory->First(); i < _nPos && pDesc; pDesc = (const ScFuncDesc*)m_pCategory->Next(),++i)
+ ;
+ return pDesc;
+}
+// -----------------------------------------------------------------------------
+sal_uInt32 ScFunctionCategory::getNumber() const
+{
+ return m_nCategory;
+}
+// -----------------------------------------------------------------------------
+
+//------------------------------------------------------------------------
+
+utl::TransliterationWrapper* ScGlobal::GetpTransliteration() //add by CHINA001
+{
+ DBG_ASSERT(
+ pTransliteration,
+ "ScGlobal::GetpTransliteration() called before ScGlobal::Init()");
+ return pTransliteration;
+}
+
+const LocaleDataWrapper* ScGlobal::GetpLocaleData()
+{
+ DBG_ASSERT(
+ pLocaleData,
+ "ScGlobal::GetpLocaleData() called before ScGlobal::Init()");
+ return pLocaleData;
+}
diff --git a/sc/source/core/data/global2.cxx b/sc/source/core/data/global2.cxx
new file mode 100644
index 000000000000..c352dbb550d6
--- /dev/null
+++ b/sc/source/core/data/global2.cxx
@@ -0,0 +1,1250 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: global2.cxx,v $
+ * $Revision: 1.23.32.2 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <unotools/textsearch.hxx>
+#include <svtools/pathoptions.hxx>
+#include <svtools/useroptions.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/charclass.hxx>
+#include <stdlib.h>
+#include <ctype.h>
+#include <svtools/syslocale.hxx>
+
+#include "global.hxx"
+#include "rangeutl.hxx"
+#include "pivot.hxx"
+#include "rechead.hxx"
+#include "compiler.hxx"
+#include "paramisc.hxx"
+
+#include "sc.hrc"
+#include "globstr.hrc"
+
+
+// -----------------------------------------------------------------------
+
+
+
+#define MAX_LABELS 256 //!!! aus fieldwnd.hxx, muss noch nach global.hxx ???
+
+//------------------------------------------------------------------------
+// struct ScImportParam:
+
+ScImportParam::ScImportParam() :
+ nCol1(0),
+ nRow1(0),
+ nCol2(0),
+ nRow2(0),
+ bImport(FALSE),
+ bNative(FALSE),
+ bSql(TRUE),
+ nType(ScDbTable)
+{
+}
+
+ScImportParam::ScImportParam( const ScImportParam& r ) :
+ nCol1 (r.nCol1),
+ nRow1 (r.nRow1),
+ nCol2 (r.nCol2),
+ nRow2 (r.nRow2),
+ bImport (r.bImport),
+ aDBName (r.aDBName),
+ aStatement (r.aStatement),
+ bNative (r.bNative),
+ bSql (r.bSql),
+ nType (r.nType)
+{
+}
+
+ScImportParam::~ScImportParam()
+{
+}
+
+void ScImportParam::Clear()
+{
+ nCol1 = nCol2 = 0;
+ nRow1 = nRow2 = 0;
+ bImport = FALSE;
+ bNative = FALSE;
+ bSql = TRUE;
+ nType = ScDbTable;
+ aDBName.Erase();
+ aStatement.Erase();
+}
+
+ScImportParam& ScImportParam::operator=( const ScImportParam& r )
+{
+ nCol1 = r.nCol1;
+ nRow1 = r.nRow1;
+ nCol2 = r.nCol2;
+ nRow2 = r.nRow2;
+ bImport = r.bImport;
+ aDBName = r.aDBName;
+ aStatement = r.aStatement;
+ bNative = r.bNative;
+ bSql = r.bSql;
+ nType = r.nType;
+
+ return *this;
+}
+
+BOOL ScImportParam::operator==( const ScImportParam& rOther ) const
+{
+ return( nCol1 == rOther.nCol1 &&
+ nRow1 == rOther.nRow1 &&
+ nCol2 == rOther.nCol2 &&
+ nRow2 == rOther.nRow2 &&
+ bImport == rOther.bImport &&
+ aDBName == rOther.aDBName &&
+ aStatement == rOther.aStatement &&
+ bNative == rOther.bNative &&
+ bSql == rOther.bSql &&
+ nType == rOther.nType );
+
+ //! nQuerySh und pConnection sind gleich ?
+}
+
+
+//------------------------------------------------------------------------
+// struct ScQueryParam:
+
+ScQueryEntry::ScQueryEntry()
+{
+ bDoQuery = FALSE;
+ bQueryByString = FALSE;
+ eOp = SC_EQUAL;
+ eConnect = SC_AND;
+ nField = 0;
+ nVal = 0.0;
+ pStr = new String;
+ pSearchParam = NULL;
+ pSearchText = NULL;
+}
+
+ScQueryEntry::ScQueryEntry(const ScQueryEntry& r)
+{
+ bDoQuery = r.bDoQuery;
+ bQueryByString = r.bQueryByString;
+ eOp = r.eOp;
+ eConnect = r.eConnect;
+ nField = r.nField;
+ nVal = r.nVal;
+ pStr = new String(*r.pStr);
+ pSearchParam = NULL;
+ pSearchText = NULL;
+}
+
+ScQueryEntry::~ScQueryEntry()
+{
+ delete pStr;
+ if ( pSearchParam )
+ {
+ delete pSearchParam;
+ delete pSearchText;
+ }
+}
+
+ScQueryEntry& ScQueryEntry::operator=( const ScQueryEntry& r )
+{
+ bDoQuery = r.bDoQuery;
+ bQueryByString = r.bQueryByString;
+ eOp = r.eOp;
+ eConnect = r.eConnect;
+ nField = r.nField;
+ nVal = r.nVal;
+ *pStr = *r.pStr;
+ if ( pSearchParam )
+ {
+ delete pSearchParam;
+ delete pSearchText;
+ }
+ pSearchParam = NULL;
+ pSearchText = NULL;
+
+ return *this;
+}
+
+void ScQueryEntry::Clear()
+{
+ bDoQuery = FALSE;
+ bQueryByString = FALSE;
+ eOp = SC_EQUAL;
+ eConnect = SC_AND;
+ nField = 0;
+ nVal = 0.0;
+ pStr->Erase();
+ if ( pSearchParam )
+ {
+ delete pSearchParam;
+ delete pSearchText;
+ }
+ pSearchParam = NULL;
+ pSearchText = NULL;
+}
+
+BOOL ScQueryEntry::operator==( const ScQueryEntry& r ) const
+{
+ return bDoQuery == r.bDoQuery
+ && bQueryByString == r.bQueryByString
+ && eOp == r.eOp
+ && eConnect == r.eConnect
+ && nField == r.nField
+ && nVal == r.nVal
+ && *pStr == *r.pStr;
+ //! pSearchParam und pSearchText nicht vergleichen
+}
+
+utl::TextSearch* ScQueryEntry::GetSearchTextPtr( BOOL bCaseSens )
+{
+ if ( !pSearchParam )
+ {
+ pSearchParam = new utl::SearchParam( *pStr, utl::SearchParam::SRCH_REGEXP,
+ bCaseSens, FALSE, FALSE );
+ pSearchText = new utl::TextSearch( *pSearchParam, *ScGlobal::pCharClass );
+ }
+ return pSearchText;
+}
+
+//------------------------------------------------------------------------
+
+ScQueryParam::ScQueryParam()
+{
+ nEntryCount = 0;
+ Clear();
+}
+
+//------------------------------------------------------------------------
+
+ScQueryParam::ScQueryParam( const ScQueryParam& r ) :
+ nCol1(r.nCol1),nRow1(r.nRow1),nCol2(r.nCol2),nRow2(r.nRow2),nTab(r.nTab),
+ bHasHeader(r.bHasHeader), bByRow(r.bByRow), bInplace(r.bInplace), bCaseSens(r.bCaseSens),
+ bRegExp(r.bRegExp), bMixedComparison(r.bMixedComparison),
+ bDuplicate(r.bDuplicate), bDestPers(r.bDestPers),
+ nDestTab(r.nDestTab), nDestCol(r.nDestCol), nDestRow(r.nDestRow)
+{
+ nEntryCount = 0;
+
+ Resize( r.nEntryCount );
+ for (USHORT i=0; i<nEntryCount; i++)
+ pEntries[i] = r.pEntries[i];
+}
+
+//------------------------------------------------------------------------
+
+ScQueryParam::~ScQueryParam()
+{
+ delete[] pEntries;
+}
+
+//------------------------------------------------------------------------
+
+void ScQueryParam::Clear()
+{
+ nCol1=nCol2=nDestCol = 0;
+ nRow1=nRow2=nDestRow = 0;
+ nDestTab = 0;
+ nTab = SCTAB_MAX;
+ bHasHeader = bCaseSens = bRegExp = bMixedComparison = FALSE;
+ bInplace = bByRow = bDuplicate = bDestPers = TRUE;
+
+ Resize( MAXQUERY );
+ for (USHORT i=0; i<MAXQUERY; i++)
+ pEntries[i].Clear();
+}
+
+//------------------------------------------------------------------------
+
+ScQueryParam& ScQueryParam::operator=( const ScQueryParam& r )
+{
+ nCol1 = r.nCol1;
+ nRow1 = r.nRow1;
+ nCol2 = r.nCol2;
+ nRow2 = r.nRow2;
+ nTab = r.nTab;
+ nDestTab = r.nDestTab;
+ nDestCol = r.nDestCol;
+ nDestRow = r.nDestRow;
+ bHasHeader = r.bHasHeader;
+ bInplace = r.bInplace;
+ bCaseSens = r.bCaseSens;
+ bRegExp = r.bRegExp;
+ bMixedComparison = r.bMixedComparison;
+ bDuplicate = r.bDuplicate;
+ bByRow = r.bByRow;
+ bDestPers = r.bDestPers;
+
+ Resize( r.nEntryCount );
+ for (USHORT i=0; i<nEntryCount; i++)
+ pEntries[i] = r.pEntries[i];
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScQueryParam::operator==( const ScQueryParam& rOther ) const
+{
+ BOOL bEqual = FALSE;
+
+ // Anzahl der Queries gleich?
+ USHORT nUsed = 0;
+ USHORT nOtherUsed = 0;
+ while ( nUsed<nEntryCount && pEntries[nUsed].bDoQuery ) ++nUsed;
+ while ( nOtherUsed<rOther.nEntryCount && rOther.pEntries[nOtherUsed].bDoQuery )
+ ++nOtherUsed;
+
+ if ( (nUsed == nOtherUsed)
+ && (nCol1 == rOther.nCol1)
+ && (nRow1 == rOther.nRow1)
+ && (nCol2 == rOther.nCol2)
+ && (nRow2 == rOther.nRow2)
+ && (nTab == rOther.nTab)
+ && (bHasHeader == rOther.bHasHeader)
+ && (bByRow == rOther.bByRow)
+ && (bInplace == rOther.bInplace)
+ && (bCaseSens == rOther.bCaseSens)
+ && (bRegExp == rOther.bRegExp)
+ && (bMixedComparison == rOther.bMixedComparison)
+ && (bDuplicate == rOther.bDuplicate)
+ && (bDestPers == rOther.bDestPers)
+ && (nDestTab == rOther.nDestTab)
+ && (nDestCol == rOther.nDestCol)
+ && (nDestRow == rOther.nDestRow) )
+ {
+ bEqual = TRUE;
+ for ( USHORT i=0; i<nUsed && bEqual; i++ )
+ bEqual = pEntries[i] == rOther.pEntries[i];
+ }
+ return bEqual;
+}
+
+//------------------------------------------------------------------------
+
+void ScQueryParam::DeleteQuery( SCSIZE nPos )
+{
+ if (nPos<nEntryCount)
+ {
+ for (SCSIZE i=nPos; i+1<nEntryCount; i++)
+ pEntries[i] = pEntries[i+1];
+
+ pEntries[nEntryCount-1].Clear();
+ }
+ else
+ {
+ DBG_ERROR("Falscher Parameter bei ScQueryParam::DeleteQuery");
+ }
+}
+
+//------------------------------------------------------------------------
+
+void ScQueryParam::Resize(SCSIZE nNew)
+{
+ if ( nNew < MAXQUERY )
+ nNew = MAXQUERY; // nie weniger als MAXQUERY
+
+ ScQueryEntry* pNewEntries = NULL;
+ if ( nNew )
+ pNewEntries = new ScQueryEntry[nNew];
+
+ SCSIZE nCopy = Min( nEntryCount, nNew );
+ for (SCSIZE i=0; i<nCopy; i++)
+ pNewEntries[i] = pEntries[i];
+
+ if ( nEntryCount )
+ delete[] pEntries;
+ nEntryCount = nNew;
+ pEntries = pNewEntries;
+}
+
+//------------------------------------------------------------------------
+
+void ScQueryParam::MoveToDest()
+{
+ if (!bInplace)
+ {
+ SCsCOL nDifX = ((SCsCOL) nDestCol) - ((SCsCOL) nCol1);
+ SCsROW nDifY = ((SCsROW) nDestRow) - ((SCsROW) nRow1);
+ SCsTAB nDifZ = ((SCsTAB) nDestTab) - ((SCsTAB) nTab);
+
+ nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nDifX );
+ nRow1 = sal::static_int_cast<SCROW>( nRow1 + nDifY );
+ nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nDifX );
+ nRow2 = sal::static_int_cast<SCROW>( nRow2 + nDifY );
+ nTab = sal::static_int_cast<SCTAB>( nTab + nDifZ );
+ for (USHORT i=0; i<nEntryCount; i++)
+ pEntries[i].nField += nDifX;
+
+ bInplace = TRUE;
+ }
+ else
+ {
+ DBG_ERROR("MoveToDest, bInplace == TRUE");
+ }
+}
+
+//------------------------------------------------------------------------
+
+void ScQueryParam::FillInExcelSyntax(String& aCellStr, SCSIZE nIndex)
+{
+ if (aCellStr.Len() > 0)
+ {
+ if ( nIndex >= nEntryCount )
+ Resize( nIndex+1 );
+
+ ScQueryEntry& rEntry = pEntries[nIndex];
+
+ rEntry.bDoQuery = TRUE;
+ // Operatoren herausfiltern
+ if (aCellStr.GetChar(0) == '<')
+ {
+ if (aCellStr.GetChar(1) == '>')
+ {
+ *rEntry.pStr = aCellStr.Copy(2);
+ rEntry.eOp = SC_NOT_EQUAL;
+ }
+ else if (aCellStr.GetChar(1) == '=')
+ {
+ *rEntry.pStr = aCellStr.Copy(2);
+ rEntry.eOp = SC_LESS_EQUAL;
+ }
+ else
+ {
+ *rEntry.pStr = aCellStr.Copy(1);
+ rEntry.eOp = SC_LESS;
+ }
+ }
+ else if (aCellStr.GetChar(0) == '>')
+ {
+ if (aCellStr.GetChar(1) == '=')
+ {
+ *rEntry.pStr = aCellStr.Copy(2);
+ rEntry.eOp = SC_GREATER_EQUAL;
+ }
+ else
+ {
+ *rEntry.pStr = aCellStr.Copy(1);
+ rEntry.eOp = SC_GREATER;
+ }
+ }
+ else
+ {
+ if (aCellStr.GetChar(0) == '=')
+ *rEntry.pStr = aCellStr.Copy(1);
+ else
+ *rEntry.pStr = aCellStr;
+ rEntry.eOp = SC_EQUAL;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// struct ScSubTotalParam:
+
+ScSubTotalParam::ScSubTotalParam()
+{
+ for ( USHORT i=0; i<MAXSUBTOTAL; i++ )
+ {
+ nSubTotals[i] = 0;
+ pSubTotals[i] = NULL;
+ pFunctions[i] = NULL;
+ }
+
+ Clear();
+}
+
+//------------------------------------------------------------------------
+
+ScSubTotalParam::ScSubTotalParam( const ScSubTotalParam& r ) :
+ nCol1(r.nCol1),nRow1(r.nRow1),nCol2(r.nCol2),nRow2(r.nRow2),
+ bRemoveOnly(r.bRemoveOnly),bReplace(r.bReplace),bPagebreak(r.bPagebreak),bCaseSens(r.bCaseSens),
+ bDoSort(r.bDoSort),bAscending(r.bAscending),bUserDef(r.bUserDef),nUserIndex(r.nUserIndex),
+ bIncludePattern(r.bIncludePattern)
+{
+ for (USHORT i=0; i<MAXSUBTOTAL; i++)
+ {
+ bGroupActive[i] = r.bGroupActive[i];
+ nField[i] = r.nField[i];
+
+ if ( (r.nSubTotals[i] > 0) && r.pSubTotals[i] && r.pFunctions[i] )
+ {
+ nSubTotals[i] = r.nSubTotals[i];
+ pSubTotals[i] = new SCCOL [r.nSubTotals[i]];
+ pFunctions[i] = new ScSubTotalFunc [r.nSubTotals[i]];
+
+ for (SCCOL j=0; j<r.nSubTotals[i]; j++)
+ {
+ pSubTotals[i][j] = r.pSubTotals[i][j];
+ pFunctions[i][j] = r.pFunctions[i][j];
+ }
+ }
+ else
+ {
+ nSubTotals[i] = 0;
+ pSubTotals[i] = NULL;
+ pFunctions[i] = NULL;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+
+void ScSubTotalParam::Clear()
+{
+ nCol1=nCol2= 0;
+ nRow1=nRow2 = 0;
+ nUserIndex = 0;
+ bPagebreak=bCaseSens=bUserDef=bIncludePattern=bRemoveOnly = FALSE;
+ bAscending=bReplace=bDoSort = TRUE;
+
+ for (USHORT i=0; i<MAXSUBTOTAL; i++)
+ {
+ bGroupActive[i] = FALSE;
+ nField[i] = 0;
+
+ if ( (nSubTotals[i] > 0) && pSubTotals[i] && pFunctions[i] )
+ {
+ for ( SCCOL j=0; j<nSubTotals[i]; j++ ) {
+ pSubTotals[i][j] = 0;
+ pFunctions[i][j] = SUBTOTAL_FUNC_NONE;
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+
+ScSubTotalParam& ScSubTotalParam::operator=( const ScSubTotalParam& r )
+{
+ nCol1 = r.nCol1;
+ nRow1 = r.nRow1;
+ nCol2 = r.nCol2;
+ nRow2 = r.nRow2;
+ bRemoveOnly = r.bRemoveOnly;
+ bReplace = r.bReplace;
+ bPagebreak = r.bPagebreak;
+ bCaseSens = r.bCaseSens;
+ bDoSort = r.bDoSort;
+ bAscending = r.bAscending;
+ bUserDef = r.bUserDef;
+ nUserIndex = r.nUserIndex;
+ bIncludePattern = r.bIncludePattern;
+
+ for (USHORT i=0; i<MAXSUBTOTAL; i++)
+ {
+ bGroupActive[i] = r.bGroupActive[i];
+ nField[i] = r.nField[i];
+ nSubTotals[i] = r.nSubTotals[i];
+
+ if ( pSubTotals[i] ) delete [] pSubTotals[i];
+ if ( pFunctions[i] ) delete [] pFunctions[i];
+
+ if ( r.nSubTotals[i] > 0 )
+ {
+ pSubTotals[i] = new SCCOL [r.nSubTotals[i]];
+ pFunctions[i] = new ScSubTotalFunc [r.nSubTotals[i]];
+
+ for (SCCOL j=0; j<r.nSubTotals[i]; j++)
+ {
+ pSubTotals[i][j] = r.pSubTotals[i][j];
+ pFunctions[i][j] = r.pFunctions[i][j];
+ }
+ }
+ else
+ {
+ nSubTotals[i] = 0;
+ pSubTotals[i] = NULL;
+ pFunctions[i] = NULL;
+ }
+ }
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScSubTotalParam::operator==( const ScSubTotalParam& rOther ) const
+{
+ BOOL bEqual = (nCol1 == rOther.nCol1)
+ && (nRow1 == rOther.nRow1)
+ && (nCol2 == rOther.nCol2)
+ && (nRow2 == rOther.nRow2)
+ && (bRemoveOnly == rOther.bRemoveOnly)
+ && (bReplace == rOther.bReplace)
+ && (bPagebreak == rOther.bPagebreak)
+ && (bDoSort == rOther.bDoSort)
+ && (bCaseSens == rOther.bCaseSens)
+ && (bAscending == rOther.bAscending)
+ && (bUserDef == rOther.bUserDef)
+ && (nUserIndex == rOther.nUserIndex)
+ && (bIncludePattern== rOther.bIncludePattern);
+
+ if ( bEqual )
+ {
+ bEqual = TRUE;
+ for ( USHORT i=0; i<MAXSUBTOTAL && bEqual; i++ )
+ {
+ bEqual = (bGroupActive[i] == rOther.bGroupActive[i])
+ && (nField[i] == rOther.nField[i])
+ && (nSubTotals[i] == rOther.nSubTotals[i]);
+
+ if ( bEqual && (nSubTotals[i] > 0) )
+ {
+ bEqual = (pSubTotals != NULL) && (pFunctions != NULL);
+
+ for (SCCOL j=0; (j<nSubTotals[i]) && bEqual; j++)
+ {
+ bEqual = bEqual
+ && (pSubTotals[i][j] == rOther.pSubTotals[i][j])
+ && (pFunctions[i][j] == rOther.pFunctions[i][j]);
+ }
+ }
+ }
+ }
+
+ return bEqual;
+}
+
+//------------------------------------------------------------------------
+
+void ScSubTotalParam::SetSubTotals( USHORT nGroup,
+ const SCCOL* ptrSubTotals,
+ const ScSubTotalFunc* ptrFunctions,
+ USHORT nCount )
+{
+ DBG_ASSERT( (nGroup <= MAXSUBTOTAL),
+ "ScSubTotalParam::SetSubTotals(): nGroup > MAXSUBTOTAL!" );
+ DBG_ASSERT( ptrSubTotals,
+ "ScSubTotalParam::SetSubTotals(): ptrSubTotals == NULL!" );
+ DBG_ASSERT( ptrFunctions,
+ "ScSubTotalParam::SetSubTotals(): ptrFunctions == NULL!" );
+ DBG_ASSERT( (nCount > 0),
+ "ScSubTotalParam::SetSubTotals(): nCount <= 0!" );
+
+ if ( ptrSubTotals && ptrFunctions && (nCount > 0) && (nGroup <= MAXSUBTOTAL) )
+ {
+ // 0 wird als 1 aufgefasst, sonst zum Array-Index dekrementieren
+ if (nGroup != 0)
+ nGroup--;
+
+ delete [] pSubTotals[nGroup];
+ delete [] pFunctions[nGroup];
+
+ pSubTotals[nGroup] = new SCCOL [nCount];
+ pFunctions[nGroup] = new ScSubTotalFunc [nCount];
+ nSubTotals[nGroup] = static_cast<SCCOL>(nCount);
+
+ for ( USHORT i=0; i<nCount; i++ )
+ {
+ pSubTotals[nGroup][i] = ptrSubTotals[i];
+ pFunctions[nGroup][i] = ptrFunctions[i];
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// struct ScConsolidateParam:
+
+ScConsolidateParam::ScConsolidateParam() :
+ ppDataAreas( NULL )
+{
+ Clear();
+}
+
+//------------------------------------------------------------------------
+
+ScConsolidateParam::ScConsolidateParam( const ScConsolidateParam& r ) :
+ nCol(r.nCol),nRow(r.nRow),nTab(r.nTab),
+ eFunction(r.eFunction),nDataAreaCount(0),
+ ppDataAreas( NULL ),
+ bByCol(r.bByCol),bByRow(r.bByRow),bReferenceData(r.bReferenceData)
+{
+ if ( r.nDataAreaCount > 0 )
+ {
+ nDataAreaCount = r.nDataAreaCount;
+ ppDataAreas = new ScArea*[nDataAreaCount];
+ for ( USHORT i=0; i<nDataAreaCount; i++ )
+ ppDataAreas[i] = new ScArea( *(r.ppDataAreas[i]) );
+ }
+}
+
+//------------------------------------------------------------------------
+
+__EXPORT ScConsolidateParam::~ScConsolidateParam()
+{
+ ClearDataAreas();
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScConsolidateParam::ClearDataAreas()
+{
+ if ( ppDataAreas )
+ {
+ for ( USHORT i=0; i<nDataAreaCount; i++ )
+ delete ppDataAreas[i];
+ delete [] ppDataAreas;
+ ppDataAreas = NULL;
+ }
+ nDataAreaCount = 0;
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScConsolidateParam::Clear()
+{
+ ClearDataAreas();
+
+ nCol = 0;
+ nRow = 0;
+ nTab = 0;
+ bByCol = bByRow = bReferenceData = FALSE;
+ eFunction = SUBTOTAL_FUNC_SUM;
+}
+
+//------------------------------------------------------------------------
+
+ScConsolidateParam& __EXPORT ScConsolidateParam::operator=( const ScConsolidateParam& r )
+{
+ nCol = r.nCol;
+ nRow = r.nRow;
+ nTab = r.nTab;
+ bByCol = r.bByCol;
+ bByRow = r.bByRow;
+ bReferenceData = r.bReferenceData;
+ eFunction = r.eFunction;
+ SetAreas( r.ppDataAreas, r.nDataAreaCount );
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+BOOL __EXPORT ScConsolidateParam::operator==( const ScConsolidateParam& r ) const
+{
+ BOOL bEqual = (nCol == r.nCol)
+ && (nRow == r.nRow)
+ && (nTab == r.nTab)
+ && (bByCol == r.bByCol)
+ && (bByRow == r.bByRow)
+ && (bReferenceData == r.bReferenceData)
+ && (nDataAreaCount == r.nDataAreaCount)
+ && (eFunction == r.eFunction);
+
+ if ( nDataAreaCount == 0 )
+ bEqual = bEqual && (ppDataAreas == NULL) && (r.ppDataAreas == NULL);
+ else
+ bEqual = bEqual && (ppDataAreas != NULL) && (r.ppDataAreas != NULL);
+
+ if ( bEqual && (nDataAreaCount > 0) )
+ for ( USHORT i=0; i<nDataAreaCount && bEqual; i++ )
+ bEqual = *(ppDataAreas[i]) == *(r.ppDataAreas[i]);
+
+ return bEqual;
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScConsolidateParam::SetAreas( ScArea* const* ppAreas, USHORT nCount )
+{
+ ClearDataAreas();
+ if ( ppAreas && nCount > 0 )
+ {
+ ppDataAreas = new ScArea*[nCount];
+ for ( USHORT i=0; i<nCount; i++ )
+ ppDataAreas[i] = new ScArea( *(ppAreas[i]) );
+ nDataAreaCount = nCount;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+PivotField::PivotField( SCsCOL nNewCol, USHORT nNewFuncMask ) :
+ nCol( nNewCol ),
+ nFuncMask( nNewFuncMask ),
+ nFuncCount( 0 )
+{
+}
+
+bool PivotField::operator==( const PivotField& r ) const
+{
+ return (nCol == r.nCol)
+ && (nFuncMask == r.nFuncMask)
+ && (nFuncCount == r.nFuncCount)
+ && (maFieldRef.ReferenceType == r.maFieldRef.ReferenceType)
+ && (maFieldRef.ReferenceField == r.maFieldRef.ReferenceField)
+ && (maFieldRef.ReferenceItemType == r.maFieldRef.ReferenceItemType)
+ && (maFieldRef.ReferenceItemName == r.maFieldRef.ReferenceItemName);
+}
+
+//------------------------------------------------------------------------
+// struct ScPivotParam:
+
+ScPivotParam::ScPivotParam()
+ : nCol(0), nRow(0), nTab(0),
+ ppLabelArr( NULL ), nLabels(0),
+ nPageCount(0), nColCount(0), nRowCount(0), nDataCount(0),
+ bIgnoreEmptyRows(FALSE), bDetectCategories(FALSE),
+ bMakeTotalCol(TRUE), bMakeTotalRow(TRUE)
+{
+}
+
+//------------------------------------------------------------------------
+
+ScPivotParam::ScPivotParam( const ScPivotParam& r )
+ : nCol( r.nCol ), nRow( r.nRow ), nTab( r.nTab ),
+ ppLabelArr( NULL ), nLabels(0),
+ nPageCount(0), nColCount(0), nRowCount(0), nDataCount(0),
+ bIgnoreEmptyRows(r.bIgnoreEmptyRows),
+ bDetectCategories(r.bDetectCategories),
+ bMakeTotalCol(r.bMakeTotalCol),
+ bMakeTotalRow(r.bMakeTotalRow)
+{
+ SetLabelData ( r.ppLabelArr, r.nLabels );
+ SetPivotArrays ( r.aPageArr, r.aColArr, r.aRowArr, r.aDataArr,
+ r.nPageCount, r.nColCount, r.nRowCount, r.nDataCount );
+}
+
+//------------------------------------------------------------------------
+
+__EXPORT ScPivotParam::~ScPivotParam()
+{
+ ClearLabelData();
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScPivotParam::Clear()
+{
+ nCol = 0;
+ nRow = 0;
+ nTab = 0;
+ bIgnoreEmptyRows = bDetectCategories = FALSE;
+ bMakeTotalCol = bMakeTotalRow = TRUE;
+ ClearLabelData();
+ ClearPivotArrays();
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScPivotParam::ClearLabelData()
+{
+ if ( (nLabels > 0) && ppLabelArr )
+ {
+ for ( SCSIZE i=0; i<nLabels; i++ )
+ delete ppLabelArr[i];
+ delete [] ppLabelArr;
+ ppLabelArr = NULL;
+ nLabels = 0;
+ }
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScPivotParam::ClearPivotArrays()
+{
+ memset( aPageArr, 0, PIVOT_MAXPAGEFIELD * sizeof(PivotField) );
+ memset( aColArr, 0, PIVOT_MAXFIELD * sizeof(PivotField) );
+ memset( aRowArr, 0, PIVOT_MAXFIELD * sizeof(PivotField) );
+ memset( aDataArr, 0, PIVOT_MAXFIELD * sizeof(PivotField) );
+ nPageCount = 0;
+ nColCount = 0;
+ nRowCount = 0;
+ nDataCount = 0;
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScPivotParam::SetLabelData( LabelData** pLabArr,
+ SCSIZE nLab )
+{
+ ClearLabelData();
+
+ if ( (nLab > 0) && pLabArr )
+ {
+ nLabels = (nLab>MAX_LABELS) ? MAX_LABELS : nLab;
+ ppLabelArr = new LabelData*[nLabels];
+ for ( SCSIZE i=0; i<nLabels; i++ )
+ ppLabelArr[i] = new LabelData( *(pLabArr[i]) );
+ }
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScPivotParam::SetPivotArrays ( const PivotField* pPageArr,
+ const PivotField* pColArr,
+ const PivotField* pRowArr,
+ const PivotField* pDataArr,
+ SCSIZE nPageCnt,
+ SCSIZE nColCnt,
+ SCSIZE nRowCnt,
+ SCSIZE nDataCnt )
+{
+ ClearPivotArrays();
+
+ if ( pPageArr && pColArr && pRowArr && pDataArr )
+ {
+ nPageCount = (nPageCnt>PIVOT_MAXPAGEFIELD) ? PIVOT_MAXPAGEFIELD : nPageCnt;
+ nColCount = (nColCnt>PIVOT_MAXFIELD) ? PIVOT_MAXFIELD : nColCnt;
+ nRowCount = (nRowCnt>PIVOT_MAXFIELD) ? PIVOT_MAXFIELD : nRowCnt;
+ nDataCount = (nDataCnt>PIVOT_MAXFIELD) ? PIVOT_MAXFIELD : nDataCnt;
+
+ memcpy( aPageArr, pPageArr, nPageCount * sizeof(PivotField) );
+ memcpy( aColArr, pColArr, nColCount * sizeof(PivotField) );
+ memcpy( aRowArr, pRowArr, nRowCount * sizeof(PivotField) );
+ memcpy( aDataArr, pDataArr, nDataCount * sizeof(PivotField) );
+ }
+}
+
+//------------------------------------------------------------------------
+
+ScPivotParam& __EXPORT ScPivotParam::operator=( const ScPivotParam& r )
+{
+ nCol = r.nCol;
+ nRow = r.nRow;
+ nTab = r.nTab;
+ bIgnoreEmptyRows = r.bIgnoreEmptyRows;
+ bDetectCategories = r.bDetectCategories;
+ bMakeTotalCol = r.bMakeTotalCol;
+ bMakeTotalRow = r.bMakeTotalRow;
+
+ SetLabelData ( r.ppLabelArr, r.nLabels );
+ SetPivotArrays ( r.aPageArr, r.aColArr, r.aRowArr, r.aDataArr,
+ r.nPageCount, r.nColCount, r.nRowCount, r.nDataCount );
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+BOOL __EXPORT ScPivotParam::operator==( const ScPivotParam& r ) const
+{
+ BOOL bEqual = (nCol == r.nCol)
+ && (nRow == r.nRow)
+ && (nTab == r.nTab)
+ && (bIgnoreEmptyRows == r.bIgnoreEmptyRows)
+ && (bDetectCategories == r.bDetectCategories)
+ && (bMakeTotalCol == r.bMakeTotalCol)
+ && (bMakeTotalRow == r.bMakeTotalRow)
+ && (nLabels == r.nLabels)
+ && (nPageCount == r.nPageCount)
+ && (nColCount == r.nColCount)
+ && (nRowCount == r.nRowCount)
+ && (nDataCount == r.nDataCount);
+
+ if ( bEqual )
+ {
+ SCSIZE i;
+
+ for ( i=0; i<nPageCount && bEqual; i++ )
+ bEqual = ( aPageArr[i] == r.aPageArr[i] );
+
+ for ( i=0; i<nColCount && bEqual; i++ )
+ bEqual = ( aColArr[i] == r.aColArr[i] );
+
+ for ( i=0; i<nRowCount && bEqual; i++ )
+ bEqual = ( aRowArr[i] == r.aRowArr[i] );
+
+ for ( i=0; i<nDataCount && bEqual; i++ )
+ bEqual = ( aDataArr[i] == r.aDataArr[i] );
+ }
+
+ return bEqual;
+}
+
+//------------------------------------------------------------------------
+// struct ScSolveParam
+
+ScSolveParam::ScSolveParam()
+ : pStrTargetVal( NULL )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScSolveParam::ScSolveParam( const ScSolveParam& r )
+ : aRefFormulaCell ( r.aRefFormulaCell ),
+ aRefVariableCell( r.aRefVariableCell ),
+ pStrTargetVal ( r.pStrTargetVal
+ ? new String(*r.pStrTargetVal)
+ : NULL )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScSolveParam::ScSolveParam( const ScAddress& rFormulaCell,
+ const ScAddress& rVariableCell,
+ const String& rTargetValStr )
+ : aRefFormulaCell ( rFormulaCell ),
+ aRefVariableCell( rVariableCell ),
+ pStrTargetVal ( new String(rTargetValStr) )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScSolveParam::~ScSolveParam()
+{
+ delete pStrTargetVal;
+}
+
+//------------------------------------------------------------------------
+
+ScSolveParam& __EXPORT ScSolveParam::operator=( const ScSolveParam& r )
+{
+ delete pStrTargetVal;
+
+ aRefFormulaCell = r.aRefFormulaCell;
+ aRefVariableCell = r.aRefVariableCell;
+ pStrTargetVal = r.pStrTargetVal
+ ? new String(*r.pStrTargetVal)
+ : NULL;
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScSolveParam::operator==( const ScSolveParam& r ) const
+{
+ BOOL bEqual = (aRefFormulaCell == r.aRefFormulaCell)
+ && (aRefVariableCell == r.aRefVariableCell);
+
+ if ( bEqual )
+ {
+ if ( !pStrTargetVal && !r.pStrTargetVal )
+ bEqual = TRUE;
+ else if ( !pStrTargetVal || !r.pStrTargetVal )
+ bEqual = FALSE;
+ else if ( pStrTargetVal && r.pStrTargetVal )
+ bEqual = ( *pStrTargetVal == *(r.pStrTargetVal) );
+ }
+
+ return bEqual;
+}
+
+
+//------------------------------------------------------------------------
+// struct ScTabOpParam
+
+ScTabOpParam::ScTabOpParam( const ScTabOpParam& r )
+ : aRefFormulaCell ( r.aRefFormulaCell ),
+ aRefFormulaEnd ( r.aRefFormulaEnd ),
+ aRefRowCell ( r.aRefRowCell ),
+ aRefColCell ( r.aRefColCell ),
+ nMode ( r.nMode )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScTabOpParam::ScTabOpParam( const ScRefAddress& rFormulaCell,
+ const ScRefAddress& rFormulaEnd,
+ const ScRefAddress& rRowCell,
+ const ScRefAddress& rColCell,
+ BYTE nMd)
+ : aRefFormulaCell ( rFormulaCell ),
+ aRefFormulaEnd ( rFormulaEnd ),
+ aRefRowCell ( rRowCell ),
+ aRefColCell ( rColCell ),
+ nMode ( nMd )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScTabOpParam& ScTabOpParam::operator=( const ScTabOpParam& r )
+{
+ aRefFormulaCell = r.aRefFormulaCell;
+ aRefFormulaEnd = r.aRefFormulaEnd;
+ aRefRowCell = r.aRefRowCell;
+ aRefColCell = r.aRefColCell;
+ nMode = r.nMode;
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+BOOL __EXPORT ScTabOpParam::operator==( const ScTabOpParam& r ) const
+{
+ return ( (aRefFormulaCell == r.aRefFormulaCell)
+ && (aRefFormulaEnd == r.aRefFormulaEnd)
+ && (aRefRowCell == r.aRefRowCell)
+ && (aRefColCell == r.aRefColCell)
+ && (nMode == r.nMode) );
+}
+
+String ScGlobal::GetAbsDocName( const String& rFileName,
+ SfxObjectShell* pShell )
+{
+ String aAbsName;
+ if ( !pShell->HasName() )
+ { // maybe relative to document path working directory
+ INetURLObject aObj;
+ SvtPathOptions aPathOpt;
+ aObj.SetSmartURL( aPathOpt.GetWorkPath() );
+ aObj.setFinalSlash(); // it IS a path
+ bool bWasAbs = true;
+ aAbsName = aObj.smartRel2Abs( rFileName, bWasAbs ).GetMainURL(INetURLObject::NO_DECODE);
+ // returned string must be encoded because it's used directly to create SfxMedium
+ }
+ else
+ {
+ const SfxMedium* pMedium = pShell->GetMedium();
+ if ( pMedium )
+ {
+ bool bWasAbs = true;
+ aAbsName = pMedium->GetURLObject().smartRel2Abs( rFileName, bWasAbs ).GetMainURL(INetURLObject::NO_DECODE);
+ }
+ else
+ { // This can't happen, but ...
+ // just to be sure to have the same encoding
+ INetURLObject aObj;
+ aObj.SetSmartURL( aAbsName );
+ aAbsName = aObj.GetMainURL(INetURLObject::NO_DECODE);
+ }
+ }
+ return aAbsName;
+}
+
+
+String ScGlobal::GetDocTabName( const String& rFileName,
+ const String& rTabName )
+{
+ String aDocTab( '\'' );
+ aDocTab += rFileName;
+ xub_StrLen nPos = 1;
+ while( (nPos = aDocTab.Search( '\'', nPos ))
+ != STRING_NOTFOUND )
+ { // escape Quotes
+ aDocTab.Insert( '\\', nPos );
+ nPos += 2;
+ }
+ aDocTab += '\'';
+ aDocTab += SC_COMPILER_FILE_TAB_SEP;
+ aDocTab += rTabName; // "'Doc'#Tab"
+ return aDocTab;
+}
+
+// ============================================================================
+
+ScSimpleSharedString::StringTable::StringTable() :
+ mnStrCount(0)
+{
+ // empty string (ID = 0)
+ maSharedStrings.push_back(String());
+ maSharedStringIds.insert( SharedStrMap::value_type(String(), mnStrCount++) );
+}
+
+ScSimpleSharedString::StringTable::StringTable(const ScSimpleSharedString::StringTable& r) :
+ maSharedStrings(r.maSharedStrings),
+ maSharedStringIds(r.maSharedStringIds),
+ mnStrCount(r.mnStrCount)
+{
+}
+
+ScSimpleSharedString::StringTable::~StringTable()
+{
+}
+
+sal_Int32 ScSimpleSharedString::StringTable::insertString(const String& aStr)
+{
+ SharedStrMap::const_iterator itr = maSharedStringIds.find(aStr),
+ itrEnd = maSharedStringIds.end();
+
+ if (itr == itrEnd)
+ {
+ // new string.
+ maSharedStrings.push_back(aStr);
+ maSharedStringIds.insert( SharedStrMap::value_type(aStr, mnStrCount) );
+ return mnStrCount++;
+ }
+
+ // existing string.
+ return itr->second;
+}
+
+sal_Int32 ScSimpleSharedString::StringTable::getStringId(const String& aStr)
+{
+ SharedStrMap::const_iterator itr = maSharedStringIds.find(aStr),
+ itrEnd = maSharedStringIds.end();
+ if (itr == itrEnd)
+ {
+ // string not found.
+ return insertString(aStr);
+ }
+ return itr->second;
+}
+
+const String* ScSimpleSharedString::StringTable::getString(sal_Int32 nId) const
+{
+ if (nId >= mnStrCount)
+ return NULL;
+
+ return &maSharedStrings[nId];
+}
+
+// ----------------------------------------------------------------------------
+
+ScSimpleSharedString::ScSimpleSharedString()
+{
+}
+
+ScSimpleSharedString::ScSimpleSharedString(const ScSimpleSharedString& r) :
+ maStringTable(r.maStringTable)
+{
+}
+
+ScSimpleSharedString::~ScSimpleSharedString()
+{
+}
+
+sal_Int32 ScSimpleSharedString::insertString(const String& aStr)
+{
+ return maStringTable.insertString(aStr);
+}
+
+const String* ScSimpleSharedString::getString(sal_Int32 nId)
+{
+ return maStringTable.getString(nId);
+}
+
+sal_Int32 ScSimpleSharedString::getStringId(const String& aStr)
+{
+ return maStringTable.getStringId(aStr);
+}
diff --git a/sc/source/core/data/globalx.cxx b/sc/source/core/data/globalx.cxx
new file mode 100644
index 000000000000..03ca187df4d2
--- /dev/null
+++ b/sc/source/core/data/globalx.cxx
@@ -0,0 +1,174 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: globalx.cxx,v $
+ * $Revision: 1.14 $
+ *
+ * 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 "callform.hxx"
+#include "global.hxx"
+#include <tools/urlobj.hxx>
+#include <ucbhelper/contentbroker.hxx>
+#include <ucbhelper/content.hxx>
+#include <unotools/localfilehelper.hxx>
+
+#include <tools/debug.hxx>
+#include <svtools/pathoptions.hxx>
+
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/ucb/XCommandEnvironment.hpp>
+#include <com/sun/star/ucb/XContentAccess.hpp>
+
+#include <com/sun/star/i18n/XOrdinalSuffix.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <comphelper/processfactory.hxx>
+#include <unotools/localedatawrapper.hxx>
+
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+
+
+// static
+void ScGlobal::InitAddIns()
+{
+ // multi paths separated by semicolons
+ SvtPathOptions aPathOpt;
+ String aMultiPath = aPathOpt.GetAddinPath();
+ if ( aMultiPath.Len() > 0 )
+ {
+ xub_StrLen nTokens = aMultiPath.GetTokenCount( ';' );
+ xub_StrLen nIndex = 0;
+ for ( xub_StrLen j=0; j<nTokens; j++ )
+ {
+ String aPath( aMultiPath.GetToken( 0, ';', nIndex ) );
+ if ( aPath.Len() > 0 )
+ {
+ // use LocalFileHelper to convert the path to a URL that always points
+ // to the file on the server
+ String aUrl;
+ if ( utl::LocalFileHelper::ConvertPhysicalNameToURL( aPath, aUrl ) )
+ aPath = aUrl;
+
+ INetURLObject aObj;
+ aObj.SetSmartURL( aPath );
+ aObj.setFinalSlash();
+ try
+ {
+ ::ucbhelper::Content aCnt( aObj.GetMainURL(INetURLObject::NO_DECODE),
+ Reference< XCommandEnvironment > () );
+ Reference< sdbc::XResultSet > xResultSet;
+ Sequence< rtl::OUString > aProps;
+ try
+ {
+ xResultSet = aCnt.createCursor(
+ aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
+ }
+ catch ( Exception& )
+ {
+ // ucb may throw different exceptions on failure now
+ // no assertion if AddIn directory doesn't exist
+ }
+
+ if ( xResultSet.is() )
+ {
+ Reference< sdbc::XRow > xRow( xResultSet, UNO_QUERY );
+ Reference< XContentAccess >
+ xContentAccess( xResultSet, UNO_QUERY );
+ try
+ {
+ if ( xResultSet->first() )
+ {
+ do
+ {
+ rtl::OUString aId( xContentAccess->queryContentIdentifierString() );
+ InitExternalFunc( aId );
+ }
+ while ( xResultSet->next() );
+ }
+ }
+ catch ( Exception& )
+ {
+ DBG_ERRORFILE( "ResultSetException catched!" );
+ }
+ }
+ }
+ catch ( Exception& )
+ {
+ DBG_ERRORFILE( "Exception catched!" );
+ }
+ catch ( ... )
+ {
+
+ DBG_ERRORFILE( "unexpected exception caught!" );
+ }
+ }
+ }
+ }
+}
+
+
+// static
+String ScGlobal::GetOrdinalSuffix( sal_Int32 nNumber)
+{
+ if (!xOrdinalSuffix.is())
+ {
+ try
+ {
+ Reference< lang::XMultiServiceFactory > xServiceManager =
+ ::comphelper::getProcessServiceFactory();
+ Reference< XInterface > xInterface =
+ xServiceManager->createInstance(
+ ::rtl::OUString::createFromAscii("com.sun.star.i18n.OrdinalSuffix"));
+ if (xInterface.is())
+ xOrdinalSuffix = Reference< i18n::XOrdinalSuffix >( xInterface, UNO_QUERY);
+ }
+ catch ( Exception& )
+ {
+ DBG_ERRORFILE( "GetOrdinalSuffix: exception caught during init" );
+ }
+ }
+ DBG_ASSERT( xOrdinalSuffix.is(), "GetOrdinalSuffix: createInstance failed");
+ if (xOrdinalSuffix.is())
+ {
+ try
+ {
+ return xOrdinalSuffix->getOrdinalSuffix( nNumber,
+ ScGlobal::pLocaleData->getLocale());
+ }
+ catch ( Exception& )
+ {
+ DBG_ERRORFILE( "GetOrdinalSuffix: exception caught during getOrdinalSuffix" );
+ }
+ }
+ return String();
+}
diff --git a/sc/source/core/data/makefile.mk b/sc/source/core/data/makefile.mk
new file mode 100644
index 000000000000..7129198c204f
--- /dev/null
+++ b/sc/source/core/data/makefile.mk
@@ -0,0 +1,166 @@
+#*************************************************************************
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# Copyright 2008 by Sun Microsystems, Inc.
+#
+# OpenOffice.org - a multi-platform office productivity suite
+#
+# $RCSfile: makefile.mk,v $
+#
+# $Revision: 1.26.100.1 $
+#
+# 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.
+#
+#*************************************************************************
+
+PRJ=..$/..$/..
+
+PRJNAME=sc
+TARGET=data
+
+PROJECTPCH4DLL=TRUE
+PROJECTPCH=core_pch
+PROJECTPCHSOURCE=..\pch\core_pch
+
+AUTOSEG=true
+
+# --- Settings -----------------------------------------------------
+
+.INCLUDE : scpre.mk
+.INCLUDE : settings.mk
+.INCLUDE : sc.mk
+.INCLUDE : $(PRJ)$/util$/makefile.pmk
+
+# --- Files --------------------------------------------------------
+
+SLOFILES = \
+ $(SLO)$/attarray.obj \
+ $(SLO)$/attrib.obj \
+ $(SLO)$/autonamecache.obj \
+ $(SLO)$/bcaslot.obj \
+ $(SLO)$/cell.obj \
+ $(SLO)$/cell2.obj \
+ $(SLO)$/column.obj \
+ $(SLO)$/column2.obj \
+ $(SLO)$/column3.obj \
+ $(SLO)$/compressedarray.obj \
+ $(SLO)$/conditio.obj \
+ $(SLO)$/dbdocutl.obj \
+ $(SLO)$/dociter.obj \
+ $(SLO)$/docpool.obj \
+ $(SLO)$/documen2.obj \
+ $(SLO)$/documen3.obj \
+ $(SLO)$/documen4.obj \
+ $(SLO)$/documen5.obj \
+ $(SLO)$/documen6.obj \
+ $(SLO)$/documen7.obj \
+ $(SLO)$/documen8.obj \
+ $(SLO)$/documen9.obj \
+ $(SLO)$/document.obj \
+ $(SLO)$/dpcachetable.obj \
+ $(SLO)$/dpdimsave.obj \
+ $(SLO)$/dpgroup.obj \
+ $(SLO)$/dpobject.obj \
+ $(SLO)$/dpoutput.obj \
+ $(SLO)$/dpsave.obj \
+ $(SLO)$/dpsdbtab.obj \
+ $(SLO)$/dpshttab.obj \
+ $(SLO)$/dptabdat.obj \
+ $(SLO)$/dptabres.obj \
+ $(SLO)$/dptabsrc.obj \
+ $(SLO)$/drawpage.obj \
+ $(SLO)$/drwlayer.obj \
+ $(SLO)$/fillinfo.obj \
+ $(SLO)$/global.obj \
+ $(SLO)$/global2.obj \
+ $(SLO)$/globalx.obj \
+ $(SLO)$/markarr.obj \
+ $(SLO)$/markdata.obj \
+ $(SLO)$/olinetab.obj \
+ $(SLO)$/pagepar.obj \
+ $(SLO)$/patattr.obj \
+ $(SLO)$/pivot.obj \
+ $(SLO)$/pivot2.obj \
+ $(SLO)$/poolhelp.obj \
+ $(SLO)$/scimpexpmsg.obj \
+ $(SLO)$/sortparam.obj \
+ $(SLO)$/stlpool.obj \
+ $(SLO)$/stlsheet.obj \
+ $(SLO)$/table1.obj \
+ $(SLO)$/table2.obj \
+ $(SLO)$/table3.obj \
+ $(SLO)$/table4.obj \
+ $(SLO)$/table5.obj \
+ $(SLO)$/table6.obj \
+ $(SLO)$/userdat.obj \
+ $(SLO)$/validat.obj \
+ $(SLO)$/postit.obj
+
+EXCEPTIONSFILES= \
+ $(SLO)$/autonamecache.obj \
+ $(SLO)$/bcaslot.obj \
+ $(SLO)$/cell2.obj \
+ $(SLO)$/column.obj \
+ $(SLO)$/column3.obj \
+ $(SLO)$/documen2.obj \
+ $(SLO)$/document.obj \
+ $(SLO)$/dpdimsave.obj \
+ $(SLO)$/dpgroup.obj \
+ $(SLO)$/dpshttab.obj \
+ $(SLO)$/dptabres.obj \
+ $(SLO)$/dptabdat.obj \
+ $(SLO)$/global2.obj \
+ $(SLO)$/table1.obj \
+ $(SLO)$/table3.obj \
+ $(SLO)$/postit.obj \
+ $(SLO)$/documen3.obj \
+ $(SLO)$/documen5.obj \
+ $(SLO)$/documen6.obj \
+ $(SLO)$/documen9.obj \
+ $(SLO)$/dpcachetable.obj \
+ $(SLO)$/dpsdbtab.obj \
+ $(SLO)$/dpobject.obj \
+ $(SLO)$/dpoutput.obj \
+ $(SLO)$/dpsave.obj \
+ $(SLO)$/dbdocutl.obj \
+ $(SLO)$/dptabsrc.obj \
+ $(SLO)$/drwlayer.obj \
+ $(SLO)$/globalx.obj
+
+.IF "$(OS)$(COM)$(CPUNAME)"=="LINUXGCCSPARC"
+NOOPTFILES= \
+ $(SLO)$/column2.obj \
+ $(SLO)$/column3.obj \
+ $(SLO)$/table3.obj \
+ $(SLO)$/table4.obj \
+ $(SLO)$/documen4.obj \
+ $(SLO)$/conditio.obj \
+ $(SLO)$/validat.obj
+EXCEPTIONSNOOPTFILES= \
+ $(SLO)$/cell.obj
+.ELSE
+EXCEPTIONSFILES+= \
+ $(SLO)$/cell.obj \
+ $(SLO)$/global.obj
+.ENDIF
+
+# --- Tagets -------------------------------------------------------
+
+.INCLUDE : target.mk
+
diff --git a/sc/source/core/data/markarr.cxx b/sc/source/core/data/markarr.cxx
new file mode 100644
index 000000000000..f5855cb4424b
--- /dev/null
+++ b/sc/source/core/data/markarr.cxx
@@ -0,0 +1,413 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: markarr.cxx,v $
+ * $Revision: 1.11.32.1 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <tools/debug.hxx>
+
+#include "markarr.hxx"
+#include "global.hxx"
+#include "address.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+//------------------------------------------------------------------------
+
+ScMarkArray::ScMarkArray() :
+ nCount( 0 ),
+ nLimit( 0 ),
+ pData( NULL )
+{
+ // special case "no marks" with pData = NULL
+}
+
+//------------------------------------------------------------------------
+
+ScMarkArray::~ScMarkArray()
+{
+ delete[] pData;
+}
+
+//------------------------------------------------------------------------
+
+void ScMarkArray::Reset( BOOL bMarked )
+{
+ // always create pData here
+ // (or have separate method to ensure pData)
+
+ delete[] pData;
+
+ nCount = nLimit = 1;
+ pData = new ScMarkEntry[1];
+ pData[0].nRow = MAXROW;
+ pData[0].bMarked = bMarked;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScMarkArray::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;
+}
+
+BOOL ScMarkArray::GetMark( SCROW nRow ) const
+{
+ SCSIZE i;
+ if (Search( nRow, i ))
+ return pData[i].bMarked;
+ else
+ return FALSE;
+
+}
+
+//------------------------------------------------------------------------
+
+void ScMarkArray::SetMarkArea( SCROW nStartRow, SCROW nEndRow, BOOL bMarked )
+{
+ if (ValidRow(nStartRow) && ValidRow(nEndRow))
+ {
+ if ((nStartRow == 0) && (nEndRow == MAXROW))
+ {
+ Reset(bMarked);
+ }
+ else
+ {
+ if (!pData)
+ Reset(FALSE); // create pData for further processing - could use special case handling!
+
+ SCSIZE nNeeded = nCount + 2;
+ if ( nLimit < nNeeded )
+ {
+ nLimit += SC_MARKARRAY_DELTA;
+ if ( nLimit < nNeeded )
+ nLimit = nNeeded;
+ ScMarkEntry* pNewData = new ScMarkEntry[nLimit];
+ memcpy( pNewData, pData, nCount*sizeof(ScMarkEntry) );
+ delete[] pData;
+ pData = pNewData;
+ }
+
+ SCSIZE ni; // number of entries in beginning
+ SCSIZE nInsert; // insert position (MAXROW+1 := no insert)
+ BOOL bCombined = FALSE;
+ BOOL bSplit = FALSE;
+ if ( nStartRow > 0 )
+ {
+ // skip beginning
+ SCSIZE nIndex;
+ Search( nStartRow, nIndex );
+ ni = nIndex;
+
+ nInsert = MAXROWCOUNT;
+ if ( pData[ni].bMarked != bMarked )
+ {
+ 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].bMarked == bMarked )
+ { // combine
+ pData[ni-1].nRow = nEndRow;
+ nInsert = MAXROWCOUNT;
+ bCombined = TRUE;
+ }
+ }
+ else
+ {
+ nInsert = 0;
+ ni = 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].bMarked == bMarked )
+ { // combine
+ if ( ni > 0 )
+ {
+ if ( pData[ni-1].bMarked == bMarked )
+ { // 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
+ }
+ if ( ni < nj )
+ { // remove middle entries
+ if ( !bCombined )
+ { // replace one entry
+ pData[ni].nRow = nEndRow;
+ pData[ni].bMarked = bMarked;
+ ni++;
+ nInsert = MAXROWCOUNT;
+ }
+ if ( ni < nj )
+ { // remove entries
+ memmove( pData + ni, pData + nj, (nCount - nj) * sizeof(ScMarkEntry) );
+ 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(ScMarkEntry) );
+ else
+ {
+ memmove( pData + nInsert + 2, pData + nInsert,
+ (nCount - nInsert) * sizeof(ScMarkEntry) );
+ pData[nInsert+1] = pData[nInsert-1];
+ nCount++;
+ }
+ }
+ if ( nInsert )
+ pData[nInsert-1].nRow = nStartRow - 1;
+ pData[nInsert].nRow = nEndRow;
+ pData[nInsert].bMarked = bMarked;
+ nCount++;
+ }
+ }
+ }
+// InfoBox(0, String(nCount) + String(" Eintraege") ).Execute();
+}
+
+void ScMarkArray::DeleteArea(SCROW nStartRow, SCROW nEndRow)
+{
+ SetMarkArea(nStartRow, nEndRow, FALSE);
+}
+
+BOOL ScMarkArray::IsAllMarked( SCROW nStartRow, SCROW nEndRow ) const
+{
+ SCSIZE nStartIndex;
+ SCSIZE nEndIndex;
+
+ if (Search( nStartRow, nStartIndex ))
+ if (pData[nStartIndex].bMarked)
+ if (Search( nEndRow, nEndIndex ))
+ if (nEndIndex==nStartIndex)
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL ScMarkArray::HasOneMark( SCROW& rStartRow, SCROW& rEndRow ) const
+{
+ BOOL bRet = FALSE;
+ if ( nCount == 1 )
+ {
+ if ( pData[0].bMarked )
+ {
+ rStartRow = 0;
+ rEndRow = MAXROW;
+ bRet = TRUE;
+ }
+ }
+ else if ( nCount == 2 )
+ {
+ if ( pData[0].bMarked )
+ {
+ rStartRow = 0;
+ rEndRow = pData[0].nRow;
+ }
+ else
+ {
+ rStartRow = pData[0].nRow + 1;
+ rEndRow = MAXROW;
+ }
+ bRet = TRUE;
+ }
+ else if ( nCount == 3 )
+ {
+ if ( pData[1].bMarked )
+ {
+ rStartRow = pData[0].nRow + 1;
+ rEndRow = pData[1].nRow;
+ bRet = TRUE;
+ }
+ }
+ return bRet;
+}
+
+void ScMarkArray::CopyMarksTo( ScMarkArray& rDestMarkArray ) const
+{
+ delete[] rDestMarkArray.pData;
+
+ if (pData)
+ {
+ rDestMarkArray.pData = new ScMarkEntry[nCount];
+ memmove( rDestMarkArray.pData, pData, nCount * sizeof(ScMarkEntry) );
+ }
+ else
+ rDestMarkArray.pData = NULL;
+
+ rDestMarkArray.nCount = rDestMarkArray.nLimit = nCount;
+}
+
+SCsROW ScMarkArray::GetNextMarked( SCsROW nRow, BOOL bUp ) const
+{
+ if (!pData)
+ const_cast<ScMarkArray*>(this)->Reset(FALSE); // create pData for further processing
+
+ SCsROW nRet = nRow;
+ if (VALIDROW(nRow))
+ {
+ SCSIZE nIndex;
+ Search(nRow, nIndex);
+ if (!pData[nIndex].bMarked)
+ {
+ if (bUp)
+ {
+ if (nIndex>0)
+ nRet = pData[nIndex-1].nRow;
+ else
+ nRet = -1;
+ }
+ else
+ nRet = pData[nIndex].nRow + 1;
+ }
+ }
+ return nRet;
+}
+
+SCROW ScMarkArray::GetMarkEnd( SCROW nRow, BOOL bUp ) const
+{
+ if (!pData)
+ const_cast<ScMarkArray*>(this)->Reset(FALSE); // create pData for further processing
+
+ SCROW nRet;
+ SCSIZE nIndex;
+ Search(nRow, nIndex);
+ DBG_ASSERT( pData[nIndex].bMarked, "GetMarkEnd ohne bMarked" );
+ if (bUp)
+ {
+ if (nIndex>0)
+ nRet = pData[nIndex-1].nRow + 1;
+ else
+ nRet = 0;
+ }
+ else
+ nRet = pData[nIndex].nRow;
+
+ return nRet;
+}
+
+//
+// -------------- Iterator ----------------------------------------------
+//
+
+ScMarkArrayIter::ScMarkArrayIter( const ScMarkArray* pNewArray ) :
+ pArray( pNewArray ),
+ nPos( 0 )
+{
+}
+
+ScMarkArrayIter::~ScMarkArrayIter()
+{
+}
+
+BOOL ScMarkArrayIter::Next( SCROW& rTop, SCROW& rBottom )
+{
+ if ( nPos >= pArray->nCount )
+ return FALSE;
+ while (!pArray->pData[nPos].bMarked)
+ {
+ ++nPos;
+ if ( nPos >= pArray->nCount )
+ return FALSE;
+ }
+ rBottom = pArray->pData[nPos].nRow;
+ if (nPos==0)
+ rTop = 0;
+ else
+ rTop = pArray->pData[nPos-1].nRow + 1;
+ ++nPos;
+ return TRUE;
+}
+
+
+
+
+
diff --git a/sc/source/core/data/markdata.cxx b/sc/source/core/data/markdata.cxx
new file mode 100644
index 000000000000..015a33928b7e
--- /dev/null
+++ b/sc/source/core/data/markdata.cxx
@@ -0,0 +1,587 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: markdata.cxx,v $
+ * $Revision: 1.8 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <tools/debug.hxx>
+
+#include "markdata.hxx"
+#include "markarr.hxx"
+#include "rangelst.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+//------------------------------------------------------------------------
+
+ScMarkData::ScMarkData() :
+ pMultiSel( NULL )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ bTabMarked[i] = FALSE;
+
+ ResetMark();
+}
+
+ScMarkData::ScMarkData(const ScMarkData& rData) :
+ aMarkRange( rData.aMarkRange ),
+ aMultiRange( rData.aMultiRange ),
+ pMultiSel( NULL )
+{
+ bMarked = rData.bMarked;
+ bMultiMarked = rData.bMultiMarked;
+ bMarking = rData.bMarking;
+ bMarkIsNeg = rData.bMarkIsNeg;
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ bTabMarked[i] = rData.bTabMarked[i];
+
+ if (rData.pMultiSel)
+ {
+ pMultiSel = new ScMarkArray[MAXCOLCOUNT];
+ for (SCCOL j=0; j<MAXCOLCOUNT; j++)
+ rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
+ }
+}
+
+ScMarkData& ScMarkData::operator=(const ScMarkData& rData)
+{
+ if ( &rData == this )
+ return *this;
+
+ delete[] pMultiSel;
+ pMultiSel = NULL;
+
+ aMarkRange = rData.aMarkRange;
+ aMultiRange = rData.aMultiRange;
+ bMarked = rData.bMarked;
+ bMultiMarked = rData.bMultiMarked;
+ bMarking = rData.bMarking;
+ bMarkIsNeg = rData.bMarkIsNeg;
+
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ bTabMarked[i] = rData.bTabMarked[i];
+
+ if (rData.pMultiSel)
+ {
+ pMultiSel = new ScMarkArray[MAXCOLCOUNT];
+ for (SCCOL j=0; j<MAXCOLCOUNT; j++)
+ rData.pMultiSel[j].CopyMarksTo( pMultiSel[j] );
+ }
+
+ return *this;
+}
+
+ScMarkData::~ScMarkData()
+{
+ delete[] pMultiSel;
+}
+
+void ScMarkData::ResetMark()
+{
+ delete[] pMultiSel;
+ pMultiSel = NULL;
+
+ bMarked = bMultiMarked = FALSE;
+ bMarking = bMarkIsNeg = FALSE;
+}
+
+void ScMarkData::SetMarkArea( const ScRange& rRange )
+{
+ aMarkRange = rRange;
+ aMarkRange.Justify();
+ if ( !bMarked )
+ {
+ // #77987# Upon creation of a document ScFormatShell GetTextAttrState
+ // may query (default) attributes although no sheet is marked yet.
+ // => mark that one.
+ if ( !GetSelectCount() )
+ bTabMarked[ aMarkRange.aStart.Tab() ] = TRUE;
+ bMarked = TRUE;
+ }
+}
+
+void ScMarkData::GetMarkArea( ScRange& rRange ) const
+{
+ rRange = aMarkRange; //! inline ?
+}
+
+void ScMarkData::GetMultiMarkArea( ScRange& rRange ) const
+{
+ rRange = aMultiRange;
+}
+
+void ScMarkData::SetMultiMarkArea( const ScRange& rRange, BOOL bMark )
+{
+ if (!pMultiSel)
+ {
+ pMultiSel = new ScMarkArray[MAXCOL+1];
+
+ // if simple mark range is set, copy to multi marks
+ if ( bMarked && !bMarkIsNeg )
+ {
+ bMarked = FALSE;
+ SetMultiMarkArea( aMarkRange, TRUE );
+ }
+ }
+
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartCol, nEndCol );
+
+ SCCOL nCol;
+ for (nCol=nStartCol; nCol<=nEndCol; nCol++)
+ pMultiSel[nCol].SetMarkArea( nStartRow, nEndRow, bMark );
+
+ if ( bMultiMarked ) // aMultiRange updaten
+ {
+ if ( nStartCol < aMultiRange.aStart.Col() )
+ aMultiRange.aStart.SetCol( nStartCol );
+ if ( nStartRow < aMultiRange.aStart.Row() )
+ aMultiRange.aStart.SetRow( nStartRow );
+ if ( nEndCol > aMultiRange.aEnd.Col() )
+ aMultiRange.aEnd.SetCol( nEndCol );
+ if ( nEndRow > aMultiRange.aEnd.Row() )
+ aMultiRange.aEnd.SetRow( nEndRow );
+ }
+ else
+ {
+ aMultiRange = rRange; // neu
+ bMultiMarked = TRUE;
+ }
+}
+
+void ScMarkData::SetAreaTab( SCTAB nTab )
+{
+ aMarkRange.aStart.SetTab(nTab);
+ aMarkRange.aEnd.SetTab(nTab);
+ aMultiRange.aStart.SetTab(nTab);
+ aMultiRange.aEnd.SetTab(nTab);
+}
+
+void ScMarkData::SelectOneTable( SCTAB nTab )
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ bTabMarked[i] = ( nTab == i );
+}
+
+SCTAB ScMarkData::GetSelectCount() const
+{
+ SCTAB nCount = 0;
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (bTabMarked[i])
+ ++nCount;
+
+ return nCount;
+}
+
+SCTAB ScMarkData::GetFirstSelected() const
+{
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ if (bTabMarked[i])
+ return i;
+
+ DBG_ERROR("GetFirstSelected: keine markiert");
+ return 0;
+}
+
+void ScMarkData::MarkToMulti()
+{
+ if ( bMarked && !bMarking )
+ {
+ SetMultiMarkArea( aMarkRange, !bMarkIsNeg );
+ bMarked = FALSE;
+
+ // check if all multi mark ranges have been removed
+ if ( bMarkIsNeg && !HasAnyMultiMarks() )
+ ResetMark();
+ }
+}
+
+void ScMarkData::MarkToSimple()
+{
+ if ( bMarking )
+ return;
+
+ if ( bMultiMarked && bMarked )
+ MarkToMulti(); // may result in bMarked and bMultiMarked reset
+
+ if ( bMultiMarked )
+ {
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ ScRange aNew = aMultiRange;
+
+ BOOL bOk = FALSE;
+ SCCOL nStartCol = aNew.aStart.Col();
+ SCCOL nEndCol = aNew.aEnd.Col();
+
+ while ( nStartCol < nEndCol && !pMultiSel[nStartCol].HasMarks() )
+ ++nStartCol;
+ while ( nStartCol < nEndCol && !pMultiSel[nEndCol].HasMarks() )
+ --nEndCol;
+
+ // Zeilen werden nur aus MarkArray genommen
+ SCROW nStartRow, nEndRow;
+ if ( pMultiSel[nStartCol].HasOneMark( nStartRow, nEndRow ) )
+ {
+ bOk = TRUE;
+ SCROW nCmpStart, nCmpEnd;
+ for (SCCOL nCol=nStartCol+1; nCol<=nEndCol && bOk; nCol++)
+ if ( !pMultiSel[nCol].HasOneMark( nCmpStart, nCmpEnd )
+ || nCmpStart != nStartRow || nCmpEnd != nEndRow )
+ bOk = FALSE;
+ }
+
+ if (bOk)
+ {
+ aNew.aStart.SetCol(nStartCol);
+ aNew.aStart.SetRow(nStartRow);
+ aNew.aEnd.SetCol(nEndCol);
+ aNew.aEnd.SetRow(nEndRow);
+
+ ResetMark();
+ aMarkRange = aNew;
+ bMarked = TRUE;
+ bMarkIsNeg = FALSE;
+ }
+ }
+}
+
+BOOL ScMarkData::IsCellMarked( SCCOL nCol, SCROW nRow, BOOL bNoSimple ) const
+{
+ if ( bMarked && !bNoSimple && !bMarkIsNeg )
+ if ( aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol &&
+ aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow )
+ return TRUE;
+
+ if (bMultiMarked)
+ {
+ //! hier auf negative Markierung testen ?
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+ return pMultiSel[nCol].GetMark( nRow );
+ }
+
+ return FALSE;
+}
+
+BOOL ScMarkData::IsColumnMarked( SCCOL nCol ) const
+{
+ // bMarkIsNeg inzwischen auch fuer Spaltenkoepfe
+ //! GetMarkColumnRanges fuer komplett markierte Spalten
+
+ if ( bMarked && !bMarkIsNeg &&
+ aMarkRange.aStart.Col() <= nCol && aMarkRange.aEnd.Col() >= nCol &&
+ aMarkRange.aStart.Row() == 0 && aMarkRange.aEnd.Row() == MAXROW )
+ return TRUE;
+
+ if ( bMultiMarked && pMultiSel[nCol].IsAllMarked(0,MAXROW) )
+ return TRUE;
+
+ return FALSE;
+}
+
+BOOL ScMarkData::IsRowMarked( SCROW nRow ) const
+{
+ // bMarkIsNeg inzwischen auch fuer Zeilenkoepfe
+ //! GetMarkRowRanges fuer komplett markierte Zeilen
+
+ if ( bMarked && !bMarkIsNeg &&
+ aMarkRange.aStart.Col() == 0 && aMarkRange.aEnd.Col() == MAXCOL &&
+ aMarkRange.aStart.Row() <= nRow && aMarkRange.aEnd.Row() >= nRow )
+ return TRUE;
+
+ if ( bMultiMarked )
+ {
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+ for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
+ if (!pMultiSel[nCol].GetMark(nRow))
+ return FALSE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void ScMarkData::MarkFromRangeList( const ScRangeList& rList, BOOL bReset )
+{
+ if (bReset)
+ {
+ for (SCTAB i=0; i<=MAXTAB; i++)
+ bTabMarked[i] = FALSE; // Tabellen sind nicht in ResetMark
+ ResetMark();
+ }
+
+ ULONG nCount = rList.Count();
+ if ( nCount == 1 && !bMarked && !bMultiMarked )
+ {
+ ScRange aRange = *rList.GetObject(0);
+ SetMarkArea( aRange );
+ SelectTable( aRange.aStart.Tab(), TRUE );
+ }
+ else
+ {
+ for (ULONG i=0; i<nCount; i++)
+ {
+ ScRange aRange = *rList.GetObject(i);
+ SetMultiMarkArea( aRange, TRUE );
+ SelectTable( aRange.aStart.Tab(), TRUE );
+ }
+ }
+}
+
+void ScMarkData::FillRangeListWithMarks( ScRangeList* pList, BOOL bClear ) const
+{
+ if (!pList)
+ return;
+
+ if (bClear)
+ pList->RemoveAll();
+
+ //! bei mehreren selektierten Tabellen mehrere Ranges eintragen !!!
+
+ if ( bMultiMarked )
+ {
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ SCTAB nTab = aMultiRange.aStart.Tab();
+
+ SCCOL nStartCol = aMultiRange.aStart.Col();
+ SCCOL nEndCol = aMultiRange.aEnd.Col();
+ for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
+ if (pMultiSel[nCol].HasMarks())
+ {
+ SCROW nTop, nBottom;
+ ScRange aRange( nCol, 0, nTab );
+ ScMarkArrayIter aMarkIter( &pMultiSel[nCol] );
+ while ( aMarkIter.Next( nTop, nBottom ) )
+ {
+ aRange.aStart.SetRow( nTop );
+ aRange.aEnd.SetRow( nBottom );
+ pList->Join( aRange );
+ }
+ }
+ }
+
+ if ( bMarked )
+ pList->Append( aMarkRange );
+}
+
+void ScMarkData::ExtendRangeListTables( ScRangeList* pList ) const
+{
+ if (!pList)
+ return;
+
+ ScRangeList aOldList(*pList);
+ pList->RemoveAll(); //! oder die vorhandenen unten weglassen
+
+ for (SCTAB nTab=0; nTab<=MAXTAB; nTab++)
+ if (bTabMarked[nTab])
+ {
+ ULONG nCount = aOldList.Count();
+ for (ULONG i=0; i<nCount; i++)
+ {
+ ScRange aRange = *aOldList.GetObject(i);
+ aRange.aStart.SetTab(nTab);
+ aRange.aEnd.SetTab(nTab);
+ pList->Append( aRange );
+ }
+ }
+}
+
+SCCOLROW ScMarkData::GetMarkColumnRanges( SCCOLROW* pRanges )
+{
+ if (bMarked)
+ MarkToMulti();
+
+ if (!bMultiMarked)
+ return 0;
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ SCCOLROW nRangeCnt = 0;
+ SCCOLROW nStart = 0;
+ while (nStart<=MAXCOL)
+ {
+ while (nStart<MAXCOL && !pMultiSel[nStart].HasMarks())
+ ++nStart;
+ if (pMultiSel[nStart].HasMarks())
+ {
+ SCCOLROW nEnd = nStart;
+ while (nEnd<MAXCOL && pMultiSel[nEnd].HasMarks())
+ ++nEnd;
+ if (!pMultiSel[nEnd].HasMarks())
+ --nEnd;
+ pRanges[2*nRangeCnt ] = nStart;
+ pRanges[2*nRangeCnt+1] = nEnd;
+ ++nRangeCnt;
+ nStart = nEnd+1;
+ }
+ else
+ nStart = MAXCOL+1;
+ }
+
+ return nRangeCnt;
+}
+
+SCCOLROW ScMarkData::GetMarkRowRanges( SCCOLROW* pRanges )
+{
+ if (bMarked)
+ MarkToMulti();
+
+ if (!bMultiMarked)
+ return 0;
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ // Welche Zeilen sind markiert?
+
+ BOOL* bRowMarked = new BOOL[MAXROW+1];
+ SCROW nRow;
+ SCCOL nCol;
+ for (nRow=0; nRow<=MAXROW; nRow++)
+ bRowMarked[nRow] = FALSE;
+
+ SCROW nTop, nBottom;
+ for (nCol=0; nCol<=MAXCOL; nCol++)
+ {
+ ScMarkArrayIter aMarkIter( &pMultiSel[nCol] );
+ while (aMarkIter.Next( nTop, nBottom ))
+ for (nRow=nTop; nRow<=nBottom; nRow++)
+ bRowMarked[nRow] = TRUE;
+ }
+
+ // zu Bereichen zusammenfassen
+
+ SCCOLROW nRangeCnt = 0;
+ SCCOLROW nStart = 0;
+ while (nStart<=MAXROW)
+ {
+ while (nStart<MAXROW && !bRowMarked[nStart])
+ ++nStart;
+ if (bRowMarked[nStart])
+ {
+ SCCOLROW nEnd = nStart;
+ while (nEnd<MAXROW && bRowMarked[nEnd])
+ ++nEnd;
+ if (!bRowMarked[nEnd])
+ --nEnd;
+ pRanges[2*nRangeCnt ] = nStart;
+ pRanges[2*nRangeCnt+1] = nEnd;
+ ++nRangeCnt;
+ nStart = nEnd+1;
+ }
+ else
+ nStart = MAXROW+1;
+ }
+
+ delete[] bRowMarked;
+ return nRangeCnt;
+}
+
+BOOL ScMarkData::IsAllMarked( const ScRange& rRange ) const
+{
+ if ( !bMultiMarked )
+ return FALSE;
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ BOOL bOk = TRUE;
+ for (SCCOL nCol=nStartCol; nCol<=nEndCol && bOk; nCol++)
+ if ( !pMultiSel[nCol].IsAllMarked( nStartRow, nEndRow ) )
+ bOk = FALSE;
+
+ return bOk;
+}
+
+SCsROW ScMarkData::GetNextMarked( SCCOL nCol, SCsROW nRow, BOOL bUp ) const
+{
+ if ( !bMultiMarked )
+ return nRow;
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ return pMultiSel[nCol].GetNextMarked( nRow, bUp );
+}
+
+BOOL ScMarkData::HasMultiMarks( SCCOL nCol ) const
+{
+ if ( !bMultiMarked )
+ return FALSE;
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ return pMultiSel[nCol].HasMarks();
+}
+
+BOOL ScMarkData::HasAnyMultiMarks() const
+{
+ if ( !bMultiMarked )
+ return FALSE;
+
+ DBG_ASSERT(pMultiSel, "bMultiMarked, aber pMultiSel == 0");
+
+ for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
+ if ( pMultiSel[nCol].HasMarks() )
+ return TRUE;
+
+ return FALSE; // nix
+}
+
+void ScMarkData::InsertTab( SCTAB nTab )
+{
+ for (SCTAB i=MAXTAB; i>nTab; i--)
+ bTabMarked[i] = bTabMarked[i-1];
+ bTabMarked[nTab] = FALSE;
+}
+
+void ScMarkData::DeleteTab( SCTAB nTab )
+{
+ for (SCTAB i=nTab; i<MAXTAB; i++)
+ bTabMarked[i] = bTabMarked[i+1];
+ bTabMarked[MAXTAB] = FALSE;
+}
+
+
+
+
+
diff --git a/sc/source/core/data/olinetab.cxx b/sc/source/core/data/olinetab.cxx
new file mode 100644
index 000000000000..11112e5774ac
--- /dev/null
+++ b/sc/source/core/data/olinetab.cxx
@@ -0,0 +1,811 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: olinetab.cxx,v $
+ * $Revision: 1.10.32.3 $
+ *
+ * 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"
+
+// System - Includes -----------------------------------------------------
+
+
+
+#include <tools/debug.hxx>
+#include <limits.h>
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "olinetab.hxx"
+#include "global.hxx"
+#include "rechead.hxx"
+#include "address.hxx"
+
+//------------------------------------------------------------------------
+
+ScOutlineEntry::ScOutlineEntry( SCCOLROW nNewStart, SCCOLROW nNewSize, BOOL bNewHidden ) :
+ nStart ( nNewStart ),
+ nSize ( nNewSize ),
+ bHidden ( bNewHidden ),
+ bVisible( TRUE )
+{
+}
+
+ScOutlineEntry::ScOutlineEntry( const ScOutlineEntry& rEntry ) :
+ ScDataObject(),
+ nStart ( rEntry.nStart ),
+ nSize ( rEntry.nSize ),
+ bHidden ( rEntry.bHidden ),
+ bVisible( rEntry.bVisible )
+{
+}
+
+ScDataObject* ScOutlineEntry::Clone() const
+{
+ return new ScOutlineEntry( *this );
+}
+
+void ScOutlineEntry::Move( SCsCOLROW nDelta )
+{
+ SCCOLROW nNewPos = nStart + nDelta;
+ if (nNewPos<0)
+ {
+ DBG_ERROR("OutlineEntry < 0");
+ nNewPos = 0;
+ }
+ nStart = nNewPos;
+}
+
+void ScOutlineEntry::SetSize( SCSIZE nNewSize )
+{
+ if (nNewSize>0)
+ nSize = nNewSize;
+ else
+ {
+ DBG_ERROR("ScOutlineEntry Size == 0");
+ }
+}
+
+void ScOutlineEntry::SetPosSize( SCCOLROW nNewPos, SCSIZE nNewSize )
+{
+ nStart = nNewPos;
+ SetSize( nNewSize );
+}
+
+void ScOutlineEntry::SetHidden( BOOL bNewHidden )
+{
+ bHidden = bNewHidden;
+}
+
+void ScOutlineEntry::SetVisible( BOOL bNewVisible )
+{
+ bVisible = bNewVisible;
+}
+
+//------------------------------------------------------------------------
+
+ScOutlineCollection::ScOutlineCollection() :
+ ScSortedCollection( 4,4,FALSE )
+{
+}
+
+inline short IntCompare( SCCOLROW nX, SCCOLROW nY )
+{
+ if ( nX==nY ) return 0;
+ else if ( nX<nY ) return -1;
+ else return 1;
+}
+
+short ScOutlineCollection::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ return IntCompare( ((ScOutlineEntry*)pKey1)->GetStart(),
+ ((ScOutlineEntry*)pKey2)->GetStart() );
+}
+
+USHORT ScOutlineCollection::FindStart( SCCOLROW nMinStart )
+{
+ //! binaer suchen ?
+
+ USHORT nPos = 0;
+ USHORT nLocalCount = GetCount();
+ while ( (nPos<nLocalCount) ? (((ScOutlineEntry*)At(nPos))->GetStart() < nMinStart) : FALSE )
+ ++nPos;
+
+ return nPos;
+}
+
+//------------------------------------------------------------------------
+
+ScOutlineArray::ScOutlineArray() :
+ nDepth( 0 )
+{
+}
+
+ScOutlineArray::ScOutlineArray( const ScOutlineArray& rArray ) :
+ nDepth( rArray.nDepth )
+{
+ for (USHORT nLevel=0; nLevel<nDepth; nLevel++)
+ {
+ USHORT nCount = rArray.aCollections[nLevel].GetCount();
+ for (USHORT nEntry=0; nEntry<nCount; nEntry++)
+ {
+ ScOutlineEntry* pEntry = (ScOutlineEntry*) rArray.aCollections[nLevel].At(nEntry);
+ aCollections[nLevel].Insert( new ScOutlineEntry( *pEntry ) );
+ }
+ }
+}
+
+void ScOutlineArray::FindEntry( SCCOLROW nSearchPos, USHORT& rFindLevel, USHORT& rFindIndex,
+ USHORT nMaxLevel )
+{
+ rFindLevel = rFindIndex = 0;
+
+ if (nMaxLevel > nDepth)
+ nMaxLevel = nDepth;
+
+ for (USHORT nLevel=0; nLevel<nMaxLevel; nLevel++) //! rueckwaerts suchen ?
+ {
+ ScOutlineCollection* pCollect = &aCollections[nLevel];
+ USHORT nCount = pCollect->GetCount();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ScOutlineEntry* pEntry = (ScOutlineEntry*) pCollect->At(i);
+ if ( pEntry->GetStart() <= nSearchPos && pEntry->GetEnd() >= nSearchPos )
+ {
+ rFindLevel = nLevel + 1; // naechster Level (zum Einfuegen)
+ rFindIndex = i;
+ }
+ }
+ }
+}
+
+BOOL ScOutlineArray::Insert( SCCOLROW nStartCol, SCCOLROW nEndCol, BOOL& rSizeChanged,
+ BOOL bHidden, BOOL bVisible )
+{
+ rSizeChanged = FALSE;
+
+ USHORT nStartLevel;
+ USHORT nStartIndex;
+ USHORT nEndLevel;
+ USHORT nEndIndex;
+ BOOL bFound = FALSE;
+
+ BOOL bCont;
+ USHORT nFindMax;
+ FindEntry( nStartCol, nStartLevel, nStartIndex ); // nLevel = neuer Level (alter+1) !!!
+ FindEntry( nEndCol, nEndLevel, nEndIndex );
+ nFindMax = Max(nStartLevel,nEndLevel);
+ do
+ {
+ bCont = FALSE;
+
+ if ( nStartLevel == nEndLevel && nStartIndex == nEndIndex && nStartLevel < SC_OL_MAXDEPTH )
+ bFound = TRUE;
+
+ if (!bFound)
+ {
+ if (nFindMax>0)
+ {
+ --nFindMax;
+ if (nStartLevel)
+ if ( ((ScOutlineEntry*)aCollections[nStartLevel-1].At(nStartIndex))->
+ GetStart() == nStartCol )
+ FindEntry( nStartCol, nStartLevel, nStartIndex, nFindMax );
+ if (nEndLevel)
+ if ( ((ScOutlineEntry*)aCollections[nEndLevel-1].At(nEndIndex))->
+ GetEnd() == nEndCol )
+ FindEntry( nEndCol, nEndLevel, nEndIndex, nFindMax );
+ bCont = TRUE;
+ }
+ }
+ }
+ while ( !bFound && bCont );
+
+ if (!bFound)
+ return FALSE;
+
+ USHORT nLevel = nStartLevel;
+
+ // untere verschieben
+
+ BOOL bNeedSize = FALSE;
+ for ( short nMoveLevel = nDepth-1; nMoveLevel >= (short) nLevel; nMoveLevel-- )
+ {
+ USHORT nCount = aCollections[nMoveLevel].GetCount();
+ BOOL bMoved = FALSE;
+ for ( USHORT i=0; i<nCount; i += bMoved ? 0 : 1 )
+ {
+ ScOutlineEntry* pEntry = (ScOutlineEntry*) aCollections[nMoveLevel].At(i);
+ SCCOLROW nEntryStart = pEntry->GetStart();
+ if ( nEntryStart >= nStartCol && nEntryStart <= nEndCol )
+ {
+ if (nMoveLevel >= SC_OL_MAXDEPTH - 1)
+ {
+ rSizeChanged = FALSE; // kein Platz
+ return FALSE;
+ }
+ aCollections[nMoveLevel+1].Insert( new ScOutlineEntry( *pEntry ) );
+ aCollections[nMoveLevel].AtFree( i );
+ nCount = aCollections[nMoveLevel].GetCount();
+ bMoved = TRUE;
+ if (nMoveLevel == (short) nDepth - 1)
+ bNeedSize = TRUE;
+ }
+ else
+ bMoved = FALSE;
+ }
+ }
+
+ if (bNeedSize)
+ {
+ ++nDepth;
+ rSizeChanged = TRUE;
+ }
+
+ if (nDepth <= nLevel)
+ {
+ nDepth = nLevel+1;
+ rSizeChanged = TRUE;
+ }
+
+/* nicht zusammenfassen!
+
+ // zusammenfassen
+
+ USHORT nCount = aCollections[nLevel].GetCount();
+ USHORT nIndex;
+ bFound = FALSE;
+ for ( nIndex=0; nIndex<nCount && !bFound; nIndex++ )
+ {
+ if ( ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetEnd() + 1 == nStartCol )
+ {
+ nStartCol = ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetStart();
+ aCollections[nLevel].AtFree(nIndex);
+ nCount = aCollections[nLevel].GetCount(); // Daten geaendert
+ bFound = TRUE;
+ }
+ }
+
+ bFound = FALSE;
+ for ( nIndex=0; nIndex<nCount && !bFound; nIndex++ )
+ {
+ if ( ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetStart() == nEndCol + 1 )
+ {
+ nEndCol = ((ScOutlineEntry*) aCollections[nLevel].At(nIndex))->GetEnd();
+ aCollections[nLevel].AtFree(nIndex);
+ bFound = TRUE;
+ }
+ }
+*/
+ ScOutlineEntry* pNewEntry = new ScOutlineEntry( nStartCol, nEndCol+1-nStartCol, bHidden );
+ pNewEntry->SetVisible( bVisible );
+ aCollections[nLevel].Insert( pNewEntry );
+
+ return TRUE;
+}
+
+BOOL ScOutlineArray::FindTouchedLevel( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, USHORT& rFindLevel ) const
+{
+ BOOL bFound = FALSE;
+ rFindLevel = 0;
+
+ for (USHORT nLevel=0; nLevel<nDepth; nLevel++)
+ {
+ const ScOutlineCollection* pCollect = &aCollections[nLevel];
+ USHORT nCount = pCollect->GetCount();
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ScOutlineEntry* pEntry = (ScOutlineEntry*) pCollect->At(i);
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ if ( ( nBlockStart>=nStart && nBlockStart<=nEnd ) ||
+ ( nBlockEnd >=nStart && nBlockEnd <=nEnd ) )
+ {
+ rFindLevel = nLevel; // wirklicher Level
+ bFound = TRUE;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+void ScOutlineArray::RemoveSub( SCCOLROW nStartPos, SCCOLROW nEndPos, USHORT nLevel )
+{
+ if ( nLevel >= nDepth )
+ return;
+ ScOutlineCollection* pCollect = &aCollections[nLevel];
+ USHORT nCount = pCollect->GetCount();
+ BOOL bFound = FALSE;
+ for ( USHORT i=0; i<nCount; i += ( bFound ? 0 : 1 ) )
+ {
+ bFound = FALSE;
+ ScOutlineEntry* pEntry = (ScOutlineEntry*) pCollect->At(i);
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ if ( nStart>=nStartPos && nEnd<=nEndPos )
+ {
+ RemoveSub( nStart, nEnd, nLevel+1 );
+ pCollect->AtFree(i);
+ nCount = pCollect->GetCount();
+ bFound = TRUE;
+ }
+ }
+}
+
+void ScOutlineArray::PromoteSub( SCCOLROW nStartPos, SCCOLROW nEndPos, USHORT nStartLevel )
+{
+ if (nStartLevel==0)
+ {
+ DBG_ERROR("PromoteSub mit Level 0");
+ return;
+ }
+
+ for (USHORT nLevel = nStartLevel; nLevel < nDepth; nLevel++)
+ {
+ ScOutlineCollection* pCollect = &aCollections[nLevel];
+ USHORT nCount = pCollect->GetCount();
+ BOOL bFound = FALSE;
+ for ( USHORT i=0; i<nCount; i += ( bFound ? 0 : 1 ) )
+ {
+ bFound = FALSE;
+ ScOutlineEntry* pEntry = (ScOutlineEntry*) pCollect->At(i);
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ if ( nStart>=nStartPos && nEnd<=nEndPos )
+ {
+ aCollections[nLevel-1].Insert( new ScOutlineEntry( *pEntry ) );
+ pCollect->AtFree(i);
+ nCount = pCollect->GetCount();
+ bFound = TRUE;
+ }
+ }
+ }
+}
+
+BOOL ScOutlineArray::DecDepth() // nDepth auf leere Levels anpassen
+{
+ BOOL bChanged = FALSE;
+ BOOL bCont;
+ do
+ {
+ bCont = FALSE;
+ if (nDepth)
+ if (aCollections[nDepth-1].GetCount() == 0)
+ {
+ --nDepth;
+ bChanged = TRUE;
+ bCont = TRUE;
+ }
+ }
+ while (bCont);
+ return bChanged;
+}
+
+BOOL ScOutlineArray::Remove( SCCOLROW nBlockStart, SCCOLROW nBlockEnd, BOOL& rSizeChanged )
+{
+ USHORT nLevel;
+ FindTouchedLevel( nBlockStart, nBlockEnd, nLevel );
+
+ ScOutlineCollection* pCollect = &aCollections[nLevel];
+ USHORT nCount = pCollect->GetCount();
+ BOOL bFound = FALSE;
+ BOOL bAny = FALSE;
+ for ( USHORT i=0; i<nCount; i += ( bFound ? 0 : 1 ) )
+ {
+ bFound = FALSE;
+ ScOutlineEntry* pEntry = (ScOutlineEntry*) pCollect->At(i);
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ if ( nBlockStart<=nEnd && nBlockEnd>=nStart )
+ {
+// RemoveSub( nStart, nEnd, nLevel+1 );
+ pCollect->AtFree(i);
+ PromoteSub( nStart, nEnd, nLevel+1 );
+ nCount = pCollect->GetCount();
+ i = pCollect->FindStart( nEnd+1 );
+ bFound = TRUE;
+ bAny = TRUE;
+ }
+ }
+
+ if (bAny) // Depth anpassen
+ if (DecDepth())
+ rSizeChanged = TRUE;
+
+ return bAny;
+}
+
+ScOutlineEntry* ScOutlineArray::GetEntry( USHORT nLevel, USHORT nIndex ) const
+{
+ return (ScOutlineEntry*)((nLevel < nDepth) ? aCollections[nLevel].At(nIndex) : NULL);
+}
+
+USHORT ScOutlineArray::GetCount( USHORT nLevel ) const
+{
+ return (nLevel < nDepth) ? aCollections[nLevel].GetCount() : 0;
+}
+
+ScOutlineEntry* ScOutlineArray::GetEntryByPos( USHORT nLevel, SCCOLROW nPos ) const
+{
+ USHORT nCount = GetCount( nLevel );
+ ScOutlineEntry* pEntry;
+
+ for (USHORT nIndex = 0; nIndex < nCount; nIndex++)
+ {
+ pEntry = GetEntry( nLevel, nIndex );
+ if ((pEntry->GetStart() <= nPos) && (nPos <= pEntry->GetEnd()))
+ return pEntry;
+ }
+ return NULL;
+}
+
+BOOL ScOutlineArray::GetEntryIndex( USHORT nLevel, SCCOLROW nPos, USHORT& rnIndex ) const
+{
+ // found entry contains passed position
+ USHORT nCount = GetCount( nLevel );
+ for ( rnIndex = 0; rnIndex < nCount; ++rnIndex )
+ {
+ const ScOutlineEntry* pEntry = GetEntry( nLevel, rnIndex );
+ if ( (pEntry->GetStart() <= nPos) && (nPos <= pEntry->GetEnd()) )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL ScOutlineArray::GetEntryIndexInRange(
+ USHORT nLevel, SCCOLROW nBlockStart, SCCOLROW nBlockEnd, USHORT& rnIndex ) const
+{
+ // found entry will be completely inside of passed range
+ USHORT nCount = GetCount( nLevel );
+ for ( rnIndex = 0; rnIndex < nCount; ++rnIndex )
+ {
+ const ScOutlineEntry* pEntry = GetEntry( nLevel, rnIndex );
+ if ( (nBlockStart <= pEntry->GetStart()) && (pEntry->GetEnd() <= nBlockEnd) )
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void ScOutlineArray::SetVisibleBelow( USHORT nLevel, USHORT nEntry, BOOL bValue, BOOL bSkipHidden )
+{
+ ScOutlineEntry* pEntry = GetEntry( nLevel, nEntry );
+ if( pEntry )
+ {
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ for (USHORT nSubLevel=nLevel+1; nSubLevel<nDepth; nSubLevel++)
+ {
+ USHORT i = 0;
+ pEntry = (ScOutlineEntry*) aCollections[nSubLevel].At(i);
+ while (pEntry)
+ {
+ if (pEntry->GetStart() >= nStart && pEntry->GetEnd() <= nEnd)
+ {
+ pEntry->SetVisible(bValue);
+
+ if (bSkipHidden)
+ if (!pEntry->IsHidden())
+ SetVisibleBelow( nSubLevel, i, bValue, TRUE );
+ }
+
+ ++i;
+ pEntry = (ScOutlineEntry*) aCollections[nSubLevel].At(i);
+ }
+
+ if (bSkipHidden)
+ nSubLevel = nDepth; // Abbruch
+ }
+ }
+}
+
+void ScOutlineArray::GetRange( SCCOLROW& rStart, SCCOLROW& rEnd ) const
+{
+ USHORT nCount = aCollections[0].GetCount();
+ if (nCount)
+ {
+ rStart = ((ScOutlineEntry*) aCollections[0].At(0))->GetStart();
+ rEnd = ((ScOutlineEntry*) aCollections[0].At(nCount-1))->GetEnd();
+ }
+ else
+ rStart = rEnd = 0;
+}
+
+void ScOutlineArray::ExtendBlock( USHORT nLevel, SCCOLROW& rBlkStart, SCCOLROW& rBlkEnd )
+{
+ USHORT nCount;
+ SCCOLROW nStart;
+ SCCOLROW nEnd;
+ USHORT i;
+ ScOutlineEntry* pEntry;
+
+ nCount = GetCount(nLevel);
+ for ( i=0; i<nCount; i++ )
+ {
+ pEntry = (ScOutlineEntry*) aCollections[nLevel].At(i);
+ nStart = pEntry->GetStart();
+ nEnd = pEntry->GetEnd();
+
+ if ( rBlkStart<=nEnd && rBlkEnd>=nStart )
+ {
+ if (nStart<rBlkStart) rBlkStart = nStart;
+ if (nEnd>rBlkEnd) rBlkEnd = nEnd;
+ }
+ }
+}
+
+BOOL ScOutlineArray::TestInsertSpace( SCSIZE nSize, SCCOLROW nMaxVal ) const
+{
+ USHORT nCount = aCollections[0].GetCount();
+ if (nCount)
+ {
+ SCCOLROW nEnd = ((ScOutlineEntry*) aCollections[0].At(nCount-1))->GetEnd();
+ return ( sal::static_int_cast<SCCOLROW>(nEnd+nSize) <= nMaxVal );
+ }
+
+ return TRUE;
+}
+
+void ScOutlineArray::InsertSpace( SCCOLROW nStartPos, SCSIZE nSize )
+{
+ ScSubOutlineIterator aIter( this );
+ ScOutlineEntry* pEntry;
+ while((pEntry=aIter.GetNext())!=NULL)
+ {
+ if ( pEntry->GetStart() >= nStartPos )
+ pEntry->Move(static_cast<SCsCOLROW>(nSize));
+ else
+ {
+ SCCOLROW nEnd = pEntry->GetEnd();
+ // immer erweitern, wenn innerhalb der Gruppe eingefuegt
+ // beim Einfuegen am Ende nur, wenn die Gruppe nicht ausgeblendet ist
+ if ( nEnd >= nStartPos || ( nEnd+1 >= nStartPos && !pEntry->IsHidden() ) )
+ {
+ SCSIZE nEntrySize = pEntry->GetSize();
+ nEntrySize += nSize;
+ pEntry->SetSize( nEntrySize );
+ }
+ }
+ }
+}
+
+BOOL ScOutlineArray::DeleteSpace( SCCOLROW nStartPos, SCSIZE nSize )
+{
+ SCCOLROW nEndPos = nStartPos + nSize - 1;
+ BOOL bNeedSave = FALSE; // Original fuer Undo benoetigt?
+ BOOL bChanged = FALSE; // fuer Test auf Level
+
+ ScSubOutlineIterator aIter( this );
+ ScOutlineEntry* pEntry;
+ while((pEntry=aIter.GetNext())!=NULL)
+ {
+ SCCOLROW nEntryStart = pEntry->GetStart();
+ SCCOLROW nEntryEnd = pEntry->GetEnd();
+ SCSIZE nEntrySize = pEntry->GetSize();
+
+ if ( nEntryEnd >= nStartPos )
+ {
+ if ( nEntryStart > nEndPos ) // rechts
+ pEntry->Move(-(static_cast<SCsCOLROW>(nSize)));
+ else if ( nEntryStart < nStartPos && nEntryEnd >= nEndPos ) // aussen
+ pEntry->SetSize( nEntrySize-nSize );
+ else
+ {
+ bNeedSave = TRUE;
+ if ( nEntryStart >= nStartPos && nEntryEnd <= nEndPos ) // innen
+ {
+ aIter.DeleteLast();
+ bChanged = TRUE;
+ }
+ else if ( nEntryStart >= nStartPos ) // rechts ueber
+ pEntry->SetPosSize( nStartPos, static_cast<SCSIZE>(nEntryEnd-nEndPos) );
+ else // links ueber
+ pEntry->SetSize( static_cast<SCSIZE>(nStartPos-nEntryStart) );
+ }
+ }
+ }
+
+ if (bChanged)
+ DecDepth();
+
+ return bNeedSave;
+}
+
+BOOL ScOutlineArray::ManualAction( SCCOLROW nStartPos, SCCOLROW nEndPos,
+ BOOL bShow, const ScBitMaskCompressedArray< SCCOLROW, BYTE>& rHiddenFlags )
+{
+ BOOL bModified = FALSE;
+ ScSubOutlineIterator aIter( this );
+ ScOutlineEntry* pEntry;
+ while((pEntry=aIter.GetNext())!=NULL)
+ {
+ SCCOLROW nEntryStart = pEntry->GetStart();
+ SCCOLROW nEntryEnd = pEntry->GetEnd();
+
+ if (nEntryEnd>=nStartPos && nEntryStart<=nEndPos)
+ {
+ if ( pEntry->IsHidden() == bShow )
+ {
+ // #i12341# hide if all columns/rows are hidden, show if at least one
+ // is visible
+
+ SCCOLROW nEnd = rHiddenFlags.GetBitStateEnd( nEntryStart,
+ CR_HIDDEN, CR_HIDDEN);
+ BOOL bAllHidden = (nEntryEnd <= nEnd && nEnd <
+ ::std::numeric_limits<SCCOLROW>::max());
+
+ BOOL bToggle = ( bShow != bAllHidden );
+ if ( bToggle )
+ {
+ pEntry->SetHidden( !bShow );
+ SetVisibleBelow( aIter.LastLevel(), aIter.LastEntry(), bShow, bShow );
+ bModified = TRUE;
+ }
+ }
+ }
+ }
+ return bModified;
+}
+
+void ScOutlineArray::RemoveAll()
+{
+ for (USHORT nLevel=0; nLevel<nDepth; nLevel++)
+ aCollections[nLevel].FreeAll();
+
+ nDepth = 0;
+}
+
+//------------------------------------------------------------------------
+
+ScOutlineTable::ScOutlineTable()
+{
+}
+
+ScOutlineTable::ScOutlineTable( const ScOutlineTable& rOutline ) :
+ aColOutline( rOutline.aColOutline ),
+ aRowOutline( rOutline.aRowOutline )
+{
+}
+
+BOOL ScOutlineTable::TestInsertCol( SCSIZE nSize )
+{
+ return aColOutline.TestInsertSpace( nSize, MAXCOL );
+}
+
+void ScOutlineTable::InsertCol( SCCOL nStartCol, SCSIZE nSize )
+{
+ aColOutline.InsertSpace( nStartCol, nSize );
+}
+
+BOOL ScOutlineTable::DeleteCol( SCCOL nStartCol, SCSIZE nSize )
+{
+ return aColOutline.DeleteSpace( nStartCol, nSize );
+}
+
+BOOL ScOutlineTable::TestInsertRow( SCSIZE nSize )
+{
+ return aRowOutline.TestInsertSpace( nSize, MAXROW );
+}
+
+void ScOutlineTable::InsertRow( SCROW nStartRow, SCSIZE nSize )
+{
+ aRowOutline.InsertSpace( nStartRow, nSize );
+}
+
+BOOL ScOutlineTable::DeleteRow( SCROW nStartRow, SCSIZE nSize )
+{
+ return aRowOutline.DeleteSpace( nStartRow, nSize );
+}
+
+//------------------------------------------------------------------------
+
+ScSubOutlineIterator::ScSubOutlineIterator( ScOutlineArray* pOutlineArray ) :
+ pArray( pOutlineArray ),
+ nStart( 0 ),
+ nEnd( SCCOLROW_MAX ), // alle durchgehen
+ nSubLevel( 0 ),
+ nSubEntry( 0 )
+{
+ nDepth = pArray->nDepth;
+}
+
+ScSubOutlineIterator::ScSubOutlineIterator( ScOutlineArray* pOutlineArray,
+ USHORT nLevel, USHORT nEntry ) :
+ pArray( pOutlineArray )
+{
+ ScOutlineEntry* pEntry = (ScOutlineEntry*) pArray->aCollections[nLevel].At(nEntry);
+ nStart = pEntry->GetStart();
+ nEnd = pEntry->GetEnd();
+ nSubLevel = nLevel + 1;
+ nSubEntry = 0;
+ nDepth = pArray->nDepth;
+}
+
+ScOutlineEntry* ScSubOutlineIterator::GetNext()
+{
+ ScOutlineEntry* pEntry;
+ BOOL bFound = FALSE;
+ do
+ {
+ if (nSubLevel >= nDepth)
+ return NULL;
+
+ pEntry = (ScOutlineEntry*) pArray->aCollections[nSubLevel].At(nSubEntry);
+ if (!pEntry)
+ {
+ nSubEntry = 0;
+ ++nSubLevel;
+ }
+ else
+ {
+ if ( pEntry->GetStart() >= nStart && pEntry->GetEnd() <= nEnd )
+ bFound = TRUE;
+ ++nSubEntry;
+ }
+ }
+ while (!bFound);
+ return pEntry; // nSubLevel gueltig, wenn pEntry != 0
+}
+
+USHORT ScSubOutlineIterator::LastLevel() const
+{
+ return nSubLevel;
+}
+
+USHORT ScSubOutlineIterator::LastEntry() const
+{
+ if (nSubEntry == 0)
+ {
+ DBG_ERROR("ScSubOutlineIterator::LastEntry vor GetNext");
+ return 0;
+ }
+ return nSubEntry-1;
+}
+
+void ScSubOutlineIterator::DeleteLast()
+{
+ if (nSubLevel >= nDepth)
+ {
+ DBG_ERROR("ScSubOutlineIterator::DeleteLast nach Ende");
+ return;
+ }
+ if (nSubEntry == 0)
+ {
+ DBG_ERROR("ScSubOutlineIterator::DeleteLast vor GetNext");
+ return;
+ }
+
+ --nSubEntry;
+ pArray->aCollections[nSubLevel].AtFree(nSubEntry);
+}
+
+
diff --git a/sc/source/core/data/pagepar.cxx b/sc/source/core/data/pagepar.cxx
new file mode 100644
index 000000000000..444f10a5df8e
--- /dev/null
+++ b/sc/source/core/data/pagepar.cxx
@@ -0,0 +1,125 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: pagepar.cxx,v $
+ * $Revision: 1.7 $
+ *
+ * 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 ---------------------------------------------------------------
+
+// System - Includes -----------------------------------------------------
+
+
+
+#include <string.h>
+
+#include "pagepar.hxx"
+
+
+//========================================================================
+// struct ScPageTableParam:
+
+ScPageTableParam::ScPageTableParam()
+{
+ Reset();
+}
+
+//------------------------------------------------------------------------
+
+ScPageTableParam::~ScPageTableParam()
+{
+}
+
+//------------------------------------------------------------------------
+
+void ScPageTableParam::Reset()
+{
+ bCellContent = TRUE;
+ bNotes=bGrid=bHeaders=bDrawings=
+ bLeftRight=bScaleAll=bScaleTo=bScalePageNum=
+ bFormulas=bNullVals=bSkipEmpty = FALSE;
+ bTopDown=bScaleNone=bCharts=bObjects = TRUE;
+ nScaleAll = 100;
+ nScalePageNum = nScaleWidth = nScaleHeight = 0;
+ nFirstPageNo = 1;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScPageTableParam::operator==( const ScPageTableParam& r ) const
+{
+ return ( memcmp( this, &r, sizeof(ScPageTableParam) ) == 0 );
+}
+
+//========================================================================
+// struct ScPageAreaParam:
+
+ScPageAreaParam::ScPageAreaParam()
+{
+ Reset();
+}
+
+//------------------------------------------------------------------------
+
+ScPageAreaParam::~ScPageAreaParam()
+{
+}
+
+//------------------------------------------------------------------------
+
+void ScPageAreaParam::Reset()
+{
+ bPrintArea = bRepeatRow = bRepeatCol = FALSE;
+
+ memset( &aPrintArea, 0, sizeof(ScRange) );
+ memset( &aRepeatRow, 0, sizeof(ScRange) );
+ memset( &aRepeatCol, 0, sizeof(ScRange) );
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScPageAreaParam::operator==( const ScPageAreaParam& r ) const
+{
+ BOOL bEqual =
+ bPrintArea == r.bPrintArea
+ && bRepeatRow == r.bRepeatRow
+ && bRepeatCol == r.bRepeatCol;
+
+ if ( bEqual )
+ if ( bPrintArea )
+ bEqual = bEqual && ( aPrintArea == r.aPrintArea );
+ if ( bEqual )
+ if ( bRepeatRow )
+ bEqual = bEqual && ( aRepeatRow == r.aRepeatRow );
+ if ( bEqual )
+ if ( bRepeatCol )
+ bEqual = bEqual && ( aRepeatCol == r.aRepeatCol );
+
+ return bEqual;
+}
diff --git a/sc/source/core/data/patattr.cxx b/sc/source/core/data/patattr.cxx
new file mode 100644
index 000000000000..5f2f3c1a4f6e
--- /dev/null
+++ b/sc/source/core/data/patattr.cxx
@@ -0,0 +1,1337 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: patattr.cxx,v $
+ * $Revision: 1.34.144.1 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/adjitem.hxx>
+#include <svx/algitem.hxx>
+#include <svx/boxitem.hxx>
+#include <svx/bolnitem.hxx>
+#include <svx/brshitem.hxx>
+#include <svx/charreliefitem.hxx>
+#include <svx/cntritem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svx/colritem.hxx>
+#include <svx/crsditem.hxx>
+#include <svx/emphitem.hxx>
+#include <svx/fhgtitem.hxx>
+#include <svx/fontitem.hxx>
+#include <svx/forbiddenruleitem.hxx>
+#include <svx/frmdiritem.hxx>
+#include <svx/langitem.hxx>
+#include <svx/postitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <svx/scriptspaceitem.hxx>
+#include <svx/scripttypeitem.hxx>
+#include <svx/shaditem.hxx>
+#include <svx/shdditem.hxx>
+#include <svx/udlnitem.hxx>
+#include <svx/wghtitem.hxx>
+#include <svx/wrlmitem.hxx>
+#include <svtools/intitem.hxx>
+#include <svtools/zforlist.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/svapp.hxx>
+
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "stlsheet.hxx"
+#include "stlpool.hxx"
+#include "document.hxx"
+#include "global.hxx"
+#include "globstr.hrc"
+#include "conditio.hxx"
+#include "validat.hxx"
+#include "scmod.hxx"
+#include "fillinfo.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+ScDocument* ScPatternAttr::pDoc = NULL;
+
+// -----------------------------------------------------------------------
+
+//! move to some header file
+inline long TwipsToHMM(long nTwips) { return (nTwips * 127 + 36) / 72; }
+inline long HMMToTwips(long nHMM) { return (nHMM * 72 + 63) / 127; }
+
+// -----------------------------------------------------------------------
+
+ScPatternAttr::ScPatternAttr( SfxItemSet* pItemSet, const String& rStyleName )
+ : SfxSetItem ( ATTR_PATTERN, pItemSet ),
+ pName ( new String( rStyleName ) ),
+ pStyle ( NULL )
+{
+}
+
+ScPatternAttr::ScPatternAttr( SfxItemSet* pItemSet, ScStyleSheet* pStyleSheet )
+ : SfxSetItem ( ATTR_PATTERN, pItemSet ),
+ pName ( NULL ),
+ pStyle ( pStyleSheet )
+{
+ if ( pStyleSheet )
+ GetItemSet().SetParent( &pStyleSheet->GetItemSet() );
+}
+
+ScPatternAttr::ScPatternAttr( SfxItemPool* pItemPool )
+ : SfxSetItem ( ATTR_PATTERN, new SfxItemSet( *pItemPool, ATTR_PATTERN_START, ATTR_PATTERN_END ) ),
+ pName ( NULL ),
+ pStyle ( NULL )
+{
+}
+
+ScPatternAttr::ScPatternAttr( const ScPatternAttr& rPatternAttr )
+ : SfxSetItem ( rPatternAttr ),
+ pStyle ( rPatternAttr.pStyle )
+{
+ if (rPatternAttr.pName)
+ pName = new String(*rPatternAttr.pName);
+ else
+ pName = NULL;
+}
+
+__EXPORT ScPatternAttr::~ScPatternAttr()
+{
+ delete pName;
+}
+
+SfxPoolItem* __EXPORT ScPatternAttr::Clone( SfxItemPool *pPool ) const
+{
+ ScPatternAttr* pPattern = new ScPatternAttr( GetItemSet().Clone(TRUE, pPool) );
+
+ pPattern->pStyle = pStyle;
+ pPattern->pName = pName ? new String(*pName) : NULL;
+
+ return pPattern;
+}
+
+inline int StrCmp( const String* pStr1, const String* pStr2 )
+{
+ return ( pStr1 ? ( pStr2 ? ( *pStr1 == *pStr2 ) : FALSE ) : ( pStr2 ? FALSE : TRUE ) );
+}
+
+inline bool EqualPatternSets( const SfxItemSet& rSet1, const SfxItemSet& rSet2 )
+{
+ // #i62090# The SfxItemSet in the SfxSetItem base class always has the same ranges
+ // (single range from ATTR_PATTERN_START to ATTR_PATTERN_END), and the items are pooled,
+ // so it's enough to compare just the pointers (Count just because it's even faster).
+
+ if ( rSet1.Count() != rSet2.Count() )
+ return false;
+
+ SfxItemArray pItems1 = rSet1.GetItems_Impl(); // inline method of SfxItemSet
+ SfxItemArray pItems2 = rSet2.GetItems_Impl();
+
+ return ( 0 == memcmp( pItems1, pItems2, (ATTR_PATTERN_END - ATTR_PATTERN_START + 1) * sizeof(pItems1[0]) ) );
+}
+
+int __EXPORT ScPatternAttr::operator==( const SfxPoolItem& rCmp ) const
+{
+ // #i62090# Use quick comparison between ScPatternAttr's ItemSets
+
+ return ( EqualPatternSets( GetItemSet(), static_cast<const ScPatternAttr&>(rCmp).GetItemSet() ) &&
+ StrCmp( GetStyleName(), static_cast<const ScPatternAttr&>(rCmp).GetStyleName() ) );
+}
+
+SfxPoolItem* __EXPORT ScPatternAttr::Create( SvStream& rStream, USHORT /* nVersion */ ) const
+{
+ String* pStr;
+ BOOL bHasStyle;
+ short eFamDummy;
+
+ rStream >> bHasStyle;
+
+ if ( bHasStyle )
+ {
+ pStr = new String;
+ rStream.ReadByteString( *pStr, rStream.GetStreamCharSet() );
+ rStream >> eFamDummy; // wg. altem Dateiformat
+ }
+ else
+ pStr = new String( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
+
+ SfxItemSet *pNewSet = new SfxItemSet( *GetItemSet().GetPool(),
+ ATTR_PATTERN_START, ATTR_PATTERN_END );
+ pNewSet->Load( rStream );
+
+ ScPatternAttr* pPattern = new ScPatternAttr( pNewSet );
+
+ pPattern->pName = pStr;
+
+ return pPattern;
+}
+
+SvStream& __EXPORT ScPatternAttr::Store(SvStream& rStream, USHORT /* nItemVersion */) const
+{
+ rStream << (BOOL)TRUE;
+
+ if ( pStyle )
+ rStream.WriteByteString( pStyle->GetName(), rStream.GetStreamCharSet() );
+ else if ( pName ) // wenn Style geloescht ist/war
+ rStream.WriteByteString( *pName, rStream.GetStreamCharSet() );
+ else
+ rStream.WriteByteString( ScGlobal::GetRscString(STR_STYLENAME_STANDARD),
+ rStream.GetStreamCharSet() );
+
+ rStream << (short)SFX_STYLE_FAMILY_PARA; // wg. altem Dateiformat
+
+ GetItemSet().Store( rStream );
+
+ return rStream;
+}
+
+SvxCellOrientation ScPatternAttr::GetCellOrientation( const SfxItemSet& rItemSet, const SfxItemSet* pCondSet )
+{
+ SvxCellOrientation eOrient = SVX_ORIENTATION_STANDARD;
+
+ if( ((const SfxBoolItem&)GetItem( ATTR_STACKED, rItemSet, pCondSet )).GetValue() )
+ {
+ eOrient = SVX_ORIENTATION_STACKED;
+ }
+ else
+ {
+ INT32 nAngle = ((const SfxInt32Item&)GetItem( ATTR_ROTATE_VALUE, rItemSet, pCondSet )).GetValue();
+ if( nAngle == 9000 )
+ eOrient = SVX_ORIENTATION_BOTTOMTOP;
+ else if( nAngle == 27000 )
+ eOrient = SVX_ORIENTATION_TOPBOTTOM;
+ }
+
+ return eOrient;
+}
+
+SvxCellOrientation ScPatternAttr::GetCellOrientation( const SfxItemSet* pCondSet ) const
+{
+ return GetCellOrientation( GetItemSet(), pCondSet );
+}
+
+void ScPatternAttr::GetFont(
+ Font& rFont, const SfxItemSet& rItemSet, ScAutoFontColorMode eAutoMode,
+ OutputDevice* pOutDev, const Fraction* pScale,
+ const SfxItemSet* pCondSet, BYTE nScript,
+ const Color* pBackConfigColor, const Color* pTextConfigColor )
+{
+ // Items auslesen
+
+ const SvxFontItem* pFontAttr;
+ UINT32 nFontHeight;
+ FontWeight eWeight;
+ FontItalic eItalic;
+ FontUnderline eUnder;
+ FontUnderline eOver;
+ BOOL bWordLine;
+ FontStrikeout eStrike;
+ BOOL bOutline;
+ BOOL bShadow;
+ FontEmphasisMark eEmphasis;
+ FontRelief eRelief;
+ Color aColor;
+
+ USHORT nFontId, nHeightId, nWeightId, nPostureId;
+ if ( nScript == SCRIPTTYPE_ASIAN )
+ {
+ nFontId = ATTR_CJK_FONT;
+ nHeightId = ATTR_CJK_FONT_HEIGHT;
+ nWeightId = ATTR_CJK_FONT_WEIGHT;
+ nPostureId = ATTR_CJK_FONT_POSTURE;
+ }
+ else if ( nScript == SCRIPTTYPE_COMPLEX )
+ {
+ nFontId = ATTR_CTL_FONT;
+ nHeightId = ATTR_CTL_FONT_HEIGHT;
+ nWeightId = ATTR_CTL_FONT_WEIGHT;
+ nPostureId = ATTR_CTL_FONT_POSTURE;
+ }
+ else
+ {
+ nFontId = ATTR_FONT;
+ nHeightId = ATTR_FONT_HEIGHT;
+ nWeightId = ATTR_FONT_WEIGHT;
+ nPostureId = ATTR_FONT_POSTURE;
+ }
+
+ if ( pCondSet )
+ {
+ const SfxPoolItem* pItem;
+
+ if ( pCondSet->GetItemState( nFontId, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( nFontId );
+ pFontAttr = (const SvxFontItem*) pItem;
+
+ if ( pCondSet->GetItemState( nHeightId, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( nHeightId );
+ nFontHeight = ((const SvxFontHeightItem*)pItem)->GetHeight();
+
+ if ( pCondSet->GetItemState( nWeightId, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( nWeightId );
+ eWeight = (FontWeight)((const SvxWeightItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( nPostureId, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( nPostureId );
+ eItalic = (FontItalic)((const SvxPostureItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_UNDERLINE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_UNDERLINE );
+ eUnder = (FontUnderline)((const SvxUnderlineItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_OVERLINE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_OVERLINE );
+ eOver = (FontUnderline)((const SvxOverlineItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_WORDLINE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_WORDLINE );
+ bWordLine = ((const SvxWordLineModeItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_CROSSEDOUT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_CROSSEDOUT );
+ eStrike = (FontStrikeout)((const SvxCrossedOutItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_CONTOUR, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_CONTOUR );
+ bOutline = ((const SvxContourItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_SHADOWED, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_SHADOWED );
+ bShadow = ((const SvxShadowedItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_EMPHASISMARK, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_EMPHASISMARK );
+ eEmphasis = ((const SvxEmphasisMarkItem*)pItem)->GetEmphasisMark();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_RELIEF, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_RELIEF );
+ eRelief = (FontRelief)((const SvxCharReliefItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_COLOR, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_FONT_COLOR );
+ aColor = ((const SvxColorItem*)pItem)->GetValue();
+ }
+ else // alles aus rItemSet
+ {
+ pFontAttr = &(const SvxFontItem&)rItemSet.Get( nFontId );
+ nFontHeight = ((const SvxFontHeightItem&)
+ rItemSet.Get( nHeightId )).GetHeight();
+ eWeight = (FontWeight)((const SvxWeightItem&)
+ rItemSet.Get( nWeightId )).GetValue();
+ eItalic = (FontItalic)((const SvxPostureItem&)
+ rItemSet.Get( nPostureId )).GetValue();
+ eUnder = (FontUnderline)((const SvxUnderlineItem&)
+ rItemSet.Get( ATTR_FONT_UNDERLINE )).GetValue();
+ eOver = (FontUnderline)((const SvxOverlineItem&)
+ rItemSet.Get( ATTR_FONT_OVERLINE )).GetValue();
+ bWordLine = ((const SvxWordLineModeItem&)
+ rItemSet.Get( ATTR_FONT_WORDLINE )).GetValue();
+ eStrike = (FontStrikeout)((const SvxCrossedOutItem&)
+ rItemSet.Get( ATTR_FONT_CROSSEDOUT )).GetValue();
+ bOutline = ((const SvxContourItem&)
+ rItemSet.Get( ATTR_FONT_CONTOUR )).GetValue();
+ bShadow = ((const SvxShadowedItem&)
+ rItemSet.Get( ATTR_FONT_SHADOWED )).GetValue();
+ eEmphasis = ((const SvxEmphasisMarkItem&)
+ rItemSet.Get( ATTR_FONT_EMPHASISMARK )).GetEmphasisMark();
+ eRelief = (FontRelief)((const SvxCharReliefItem&)
+ rItemSet.Get( ATTR_FONT_RELIEF )).GetValue();
+ aColor = ((const SvxColorItem&)
+ rItemSet.Get( ATTR_FONT_COLOR )).GetValue();
+ }
+ DBG_ASSERT(pFontAttr,"nanu?");
+
+ // auswerten
+
+ // FontItem:
+
+ if (rFont.GetName() != pFontAttr->GetFamilyName())
+ rFont.SetName( pFontAttr->GetFamilyName() );
+ if (rFont.GetStyleName() != pFontAttr->GetStyleName())
+ rFont.SetStyleName( pFontAttr->GetStyleName() );
+
+ rFont.SetFamily( pFontAttr->GetFamily() );
+ rFont.SetCharSet( pFontAttr->GetCharSet() );
+ rFont.SetPitch( pFontAttr->GetPitch() );
+
+ // Groesse
+
+ if ( pOutDev != NULL )
+ {
+ Size aEffSize;
+ Fraction aFraction( 1,1 );
+ if (pScale)
+ aFraction = *pScale;
+ Size aSize( 0, (long) nFontHeight );
+ MapMode aDestMode = pOutDev->GetMapMode();
+ MapMode aSrcMode( MAP_TWIP, Point(), aFraction, aFraction );
+ if (aDestMode.GetMapUnit() == MAP_PIXEL)
+ aEffSize = pOutDev->LogicToPixel( aSize, aSrcMode );
+ else
+ {
+ Fraction aFractOne(1,1);
+ aDestMode.SetScaleX( aFractOne );
+ aDestMode.SetScaleY( aFractOne );
+ aEffSize = OutputDevice::LogicToLogic( aSize, aSrcMode, aDestMode );
+ }
+ rFont.SetSize( aEffSize );
+ }
+ else /* if pOutDev != NULL */
+ {
+ rFont.SetSize( Size( 0, (long) nFontHeight ) );
+ }
+
+ // determine effective font color
+
+ if ( ( aColor.GetColor() == COL_AUTO && eAutoMode != SC_AUTOCOL_RAW ) ||
+ eAutoMode == SC_AUTOCOL_IGNOREFONT || eAutoMode == SC_AUTOCOL_IGNOREALL )
+ {
+ if ( eAutoMode == SC_AUTOCOL_BLACK )
+ aColor.SetColor( COL_BLACK );
+ else
+ {
+ // get background color from conditional or own set
+ Color aBackColor;
+ if ( pCondSet )
+ {
+ const SfxPoolItem* pItem;
+ if ( pCondSet->GetItemState( ATTR_BACKGROUND, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rItemSet.Get( ATTR_BACKGROUND );
+ aBackColor = ((const SvxBrushItem*)pItem)->GetColor();
+ }
+ else
+ aBackColor = ((const SvxBrushItem&)rItemSet.Get( ATTR_BACKGROUND )).GetColor();
+
+ // if background color attribute is transparent, use window color for brightness comparisons
+ if ( aBackColor == COL_TRANSPARENT ||
+ eAutoMode == SC_AUTOCOL_IGNOREBACK || eAutoMode == SC_AUTOCOL_IGNOREALL )
+ {
+ if ( eAutoMode == SC_AUTOCOL_PRINT )
+ aBackColor.SetColor( COL_WHITE );
+ else if ( pBackConfigColor )
+ {
+ // pBackConfigColor can be used to avoid repeated lookup of the configured color
+ aBackColor = *pBackConfigColor;
+ }
+ else
+ aBackColor.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
+ }
+
+ // get system text color for comparison
+ Color aSysTextColor;
+ if ( eAutoMode == SC_AUTOCOL_PRINT )
+ aSysTextColor.SetColor( COL_BLACK );
+ else if ( pTextConfigColor )
+ {
+ // pTextConfigColor can be used to avoid repeated lookup of the configured color
+ aSysTextColor = *pTextConfigColor;
+ }
+ else
+ aSysTextColor.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
+
+ // select the resulting color
+ if ( aBackColor.IsDark() && aSysTextColor.IsDark() )
+ {
+ // use white instead of dark on dark
+ aColor.SetColor( COL_WHITE );
+ }
+ else if ( aBackColor.IsBright() && aSysTextColor.IsBright() )
+ {
+ // use black instead of bright on bright
+ aColor.SetColor( COL_BLACK );
+ }
+ else
+ {
+ // use aSysTextColor (black for SC_AUTOCOL_PRINT, from style settings otherwise)
+ aColor = aSysTextColor;
+ }
+ }
+ }
+
+ // set font effects
+ rFont.SetWeight( eWeight );
+ rFont.SetItalic( eItalic );
+ rFont.SetUnderline( eUnder );
+ rFont.SetOverline( eOver );
+ rFont.SetWordLineMode( bWordLine );
+ rFont.SetStrikeout( eStrike );
+ rFont.SetOutline( bOutline );
+ rFont.SetShadow( bShadow );
+ rFont.SetEmphasisMark( eEmphasis );
+ rFont.SetRelief( eRelief );
+ rFont.SetColor( aColor );
+ rFont.SetTransparent( TRUE );
+}
+
+void ScPatternAttr::GetFont(
+ Font& rFont, ScAutoFontColorMode eAutoMode,
+ OutputDevice* pOutDev, const Fraction* pScale,
+ const SfxItemSet* pCondSet, BYTE nScript,
+ const Color* pBackConfigColor, const Color* pTextConfigColor ) const
+{
+ GetFont( rFont, GetItemSet(), eAutoMode, pOutDev, pScale, pCondSet, nScript, pBackConfigColor, pTextConfigColor );
+}
+
+
+void ScPatternAttr::FillToEditItemSet( SfxItemSet& rEditSet, const SfxItemSet& rSrcSet, const SfxItemSet* pCondSet )
+{
+ // Items auslesen
+
+ SvxColorItem aColorItem(EE_CHAR_COLOR); // use item as-is
+ SvxFontItem aFontItem(EE_CHAR_FONTINFO); // use item as-is
+ SvxFontItem aCjkFontItem(EE_CHAR_FONTINFO_CJK);
+ SvxFontItem aCtlFontItem(EE_CHAR_FONTINFO_CTL);
+ long nTHeight, nCjkTHeight, nCtlTHeight; // Twips
+ FontWeight eWeight, eCjkWeight, eCtlWeight;
+ SvxUnderlineItem aUnderlineItem(UNDERLINE_NONE, EE_CHAR_UNDERLINE);
+ SvxOverlineItem aOverlineItem(UNDERLINE_NONE, EE_CHAR_OVERLINE);
+ BOOL bWordLine;
+ FontStrikeout eStrike;
+ FontItalic eItalic, eCjkItalic, eCtlItalic;
+ BOOL bOutline;
+ BOOL bShadow;
+ BOOL bForbidden;
+ FontEmphasisMark eEmphasis;
+ FontRelief eRelief;
+ LanguageType eLang, eCjkLang, eCtlLang;
+ BOOL bHyphenate;
+ SvxFrameDirection eDirection;
+
+ //! additional parameter to control if language is needed?
+
+ if ( pCondSet )
+ {
+ const SfxPoolItem* pItem;
+
+ if ( pCondSet->GetItemState( ATTR_FONT_COLOR, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_COLOR );
+ aColorItem = *(const SvxColorItem*)pItem;
+
+ if ( pCondSet->GetItemState( ATTR_FONT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT );
+ aFontItem = *(const SvxFontItem*)pItem;
+ if ( pCondSet->GetItemState( ATTR_CJK_FONT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CJK_FONT );
+ aCjkFontItem = *(const SvxFontItem*)pItem;
+ if ( pCondSet->GetItemState( ATTR_CTL_FONT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CTL_FONT );
+ aCtlFontItem = *(const SvxFontItem*)pItem;
+
+ if ( pCondSet->GetItemState( ATTR_FONT_HEIGHT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_HEIGHT );
+ nTHeight = ((const SvxFontHeightItem*)pItem)->GetHeight();
+ if ( pCondSet->GetItemState( ATTR_CJK_FONT_HEIGHT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CJK_FONT_HEIGHT );
+ nCjkTHeight = ((const SvxFontHeightItem*)pItem)->GetHeight();
+ if ( pCondSet->GetItemState( ATTR_CTL_FONT_HEIGHT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CTL_FONT_HEIGHT );
+ nCtlTHeight = ((const SvxFontHeightItem*)pItem)->GetHeight();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_WEIGHT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_WEIGHT );
+ eWeight = (FontWeight)((const SvxWeightItem*)pItem)->GetValue();
+ if ( pCondSet->GetItemState( ATTR_CJK_FONT_WEIGHT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CJK_FONT_WEIGHT );
+ eCjkWeight = (FontWeight)((const SvxWeightItem*)pItem)->GetValue();
+ if ( pCondSet->GetItemState( ATTR_CTL_FONT_WEIGHT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CTL_FONT_WEIGHT );
+ eCtlWeight = (FontWeight)((const SvxWeightItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_POSTURE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_POSTURE );
+ eItalic = (FontItalic)((const SvxPostureItem*)pItem)->GetValue();
+ if ( pCondSet->GetItemState( ATTR_CJK_FONT_POSTURE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CJK_FONT_POSTURE );
+ eCjkItalic = (FontItalic)((const SvxPostureItem*)pItem)->GetValue();
+ if ( pCondSet->GetItemState( ATTR_CTL_FONT_POSTURE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CTL_FONT_POSTURE );
+ eCtlItalic = (FontItalic)((const SvxPostureItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_UNDERLINE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_UNDERLINE );
+ aUnderlineItem = *(const SvxUnderlineItem*)pItem;
+
+ if ( pCondSet->GetItemState( ATTR_FONT_OVERLINE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_OVERLINE );
+ aOverlineItem = *(const SvxOverlineItem*)pItem;
+
+ if ( pCondSet->GetItemState( ATTR_FONT_WORDLINE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_WORDLINE );
+ bWordLine = ((const SvxWordLineModeItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_CROSSEDOUT, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_CROSSEDOUT );
+ eStrike = (FontStrikeout)((const SvxCrossedOutItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_CONTOUR, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_CONTOUR );
+ bOutline = ((const SvxContourItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_SHADOWED, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_SHADOWED );
+ bShadow = ((const SvxShadowedItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FORBIDDEN_RULES, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FORBIDDEN_RULES );
+ bForbidden = ((const SvxForbiddenRuleItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_EMPHASISMARK, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_EMPHASISMARK );
+ eEmphasis = ((const SvxEmphasisMarkItem*)pItem)->GetEmphasisMark();
+ if ( pCondSet->GetItemState( ATTR_FONT_RELIEF, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_RELIEF );
+ eRelief = (FontRelief)((const SvxCharReliefItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_FONT_LANGUAGE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_FONT_LANGUAGE );
+ eLang = ((const SvxLanguageItem*)pItem)->GetLanguage();
+ if ( pCondSet->GetItemState( ATTR_CJK_FONT_LANGUAGE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CJK_FONT_LANGUAGE );
+ eCjkLang = ((const SvxLanguageItem*)pItem)->GetLanguage();
+ if ( pCondSet->GetItemState( ATTR_CTL_FONT_LANGUAGE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_CTL_FONT_LANGUAGE );
+ eCtlLang = ((const SvxLanguageItem*)pItem)->GetLanguage();
+
+ if ( pCondSet->GetItemState( ATTR_HYPHENATE, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_HYPHENATE );
+ bHyphenate = ((const SfxBoolItem*)pItem)->GetValue();
+
+ if ( pCondSet->GetItemState( ATTR_WRITINGDIR, TRUE, &pItem ) != SFX_ITEM_SET )
+ pItem = &rSrcSet.Get( ATTR_WRITINGDIR );
+ eDirection = (SvxFrameDirection)((const SvxFrameDirectionItem*)pItem)->GetValue();
+ }
+ else // alles direkt aus Pattern
+ {
+ aColorItem = (const SvxColorItem&) rSrcSet.Get( ATTR_FONT_COLOR );
+ aFontItem = (const SvxFontItem&) rSrcSet.Get( ATTR_FONT );
+ aCjkFontItem = (const SvxFontItem&) rSrcSet.Get( ATTR_CJK_FONT );
+ aCtlFontItem = (const SvxFontItem&) rSrcSet.Get( ATTR_CTL_FONT );
+ nTHeight = ((const SvxFontHeightItem&)
+ rSrcSet.Get( ATTR_FONT_HEIGHT )).GetHeight();
+ nCjkTHeight = ((const SvxFontHeightItem&)
+ rSrcSet.Get( ATTR_CJK_FONT_HEIGHT )).GetHeight();
+ nCtlTHeight = ((const SvxFontHeightItem&)
+ rSrcSet.Get( ATTR_CTL_FONT_HEIGHT )).GetHeight();
+ eWeight = (FontWeight)((const SvxWeightItem&)
+ rSrcSet.Get( ATTR_FONT_WEIGHT )).GetValue();
+ eCjkWeight = (FontWeight)((const SvxWeightItem&)
+ rSrcSet.Get( ATTR_CJK_FONT_WEIGHT )).GetValue();
+ eCtlWeight = (FontWeight)((const SvxWeightItem&)
+ rSrcSet.Get( ATTR_CTL_FONT_WEIGHT )).GetValue();
+ eItalic = (FontItalic)((const SvxPostureItem&)
+ rSrcSet.Get( ATTR_FONT_POSTURE )).GetValue();
+ eCjkItalic = (FontItalic)((const SvxPostureItem&)
+ rSrcSet.Get( ATTR_CJK_FONT_POSTURE )).GetValue();
+ eCtlItalic = (FontItalic)((const SvxPostureItem&)
+ rSrcSet.Get( ATTR_CTL_FONT_POSTURE )).GetValue();
+ aUnderlineItem = (const SvxUnderlineItem&) rSrcSet.Get( ATTR_FONT_UNDERLINE );
+ aOverlineItem = (const SvxOverlineItem&) rSrcSet.Get( ATTR_FONT_OVERLINE );
+ bWordLine = ((const SvxWordLineModeItem&)
+ rSrcSet.Get( ATTR_FONT_WORDLINE )).GetValue();
+ eStrike = (FontStrikeout)((const SvxCrossedOutItem&)
+ rSrcSet.Get( ATTR_FONT_CROSSEDOUT )).GetValue();
+ bOutline = ((const SvxContourItem&)
+ rSrcSet.Get( ATTR_FONT_CONTOUR )).GetValue();
+ bShadow = ((const SvxShadowedItem&)
+ rSrcSet.Get( ATTR_FONT_SHADOWED )).GetValue();
+ bForbidden = ((const SvxForbiddenRuleItem&)
+ rSrcSet.Get( ATTR_FORBIDDEN_RULES )).GetValue();
+ eEmphasis = ((const SvxEmphasisMarkItem&)
+ rSrcSet.Get( ATTR_FONT_EMPHASISMARK )).GetEmphasisMark();
+ eRelief = (FontRelief)((const SvxCharReliefItem&)
+ rSrcSet.Get( ATTR_FONT_RELIEF )).GetValue();
+ eLang = ((const SvxLanguageItem&)
+ rSrcSet.Get( ATTR_FONT_LANGUAGE )).GetLanguage();
+ eCjkLang = ((const SvxLanguageItem&)
+ rSrcSet.Get( ATTR_CJK_FONT_LANGUAGE )).GetLanguage();
+ eCtlLang = ((const SvxLanguageItem&)
+ rSrcSet.Get( ATTR_CTL_FONT_LANGUAGE )).GetLanguage();
+ bHyphenate = ((const SfxBoolItem&)
+ rSrcSet.Get( ATTR_HYPHENATE )).GetValue();
+ eDirection = (SvxFrameDirection)((const SvxFrameDirectionItem&)
+ rSrcSet.Get( ATTR_WRITINGDIR )).GetValue();
+ }
+
+ // kompatibel zu LogicToLogic rechnen, also 2540/1440 = 127/72, und runden
+
+ long nHeight = TwipsToHMM(nTHeight);
+ long nCjkHeight = TwipsToHMM(nCjkTHeight);
+ long nCtlHeight = TwipsToHMM(nCtlTHeight);
+
+ // put items into EditEngine ItemSet
+
+ if ( aColorItem.GetValue().GetColor() == COL_AUTO )
+ {
+ // #108979# When cell attributes are converted to EditEngine paragraph attributes,
+ // don't create a hard item for automatic color, because that would be converted
+ // to black when the item's Store method is used in CreateTransferable/WriteBin.
+ // COL_AUTO is the EditEngine's pool default, so ClearItem will result in automatic
+ // color, too, without having to store the item.
+ rEditSet.ClearItem( EE_CHAR_COLOR );
+ }
+ else
+ rEditSet.Put( aColorItem );
+ rEditSet.Put( aFontItem );
+ rEditSet.Put( aCjkFontItem );
+ rEditSet.Put( aCtlFontItem );
+ rEditSet.Put( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
+ rEditSet.Put( SvxFontHeightItem( nCjkHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
+ rEditSet.Put( SvxFontHeightItem( nCtlHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
+ rEditSet.Put( SvxWeightItem ( eWeight, EE_CHAR_WEIGHT ) );
+ rEditSet.Put( SvxWeightItem ( eCjkWeight, EE_CHAR_WEIGHT_CJK ) );
+ rEditSet.Put( SvxWeightItem ( eCtlWeight, EE_CHAR_WEIGHT_CTL ) );
+ rEditSet.Put( aUnderlineItem );
+ rEditSet.Put( aOverlineItem );
+ rEditSet.Put( SvxWordLineModeItem( bWordLine, EE_CHAR_WLM ) );
+ rEditSet.Put( SvxCrossedOutItem( eStrike, EE_CHAR_STRIKEOUT ) );
+ rEditSet.Put( SvxPostureItem ( eItalic, EE_CHAR_ITALIC ) );
+ rEditSet.Put( SvxPostureItem ( eCjkItalic, EE_CHAR_ITALIC_CJK ) );
+ rEditSet.Put( SvxPostureItem ( eCtlItalic, EE_CHAR_ITALIC_CTL ) );
+ rEditSet.Put( SvxContourItem ( bOutline, EE_CHAR_OUTLINE ) );
+ rEditSet.Put( SvxShadowedItem ( bShadow, EE_CHAR_SHADOW ) );
+ rEditSet.Put( SfxBoolItem ( EE_PARA_FORBIDDENRULES, bForbidden ) );
+ rEditSet.Put( SvxEmphasisMarkItem( eEmphasis, EE_CHAR_EMPHASISMARK ) );
+ rEditSet.Put( SvxCharReliefItem( eRelief, EE_CHAR_RELIEF ) );
+ rEditSet.Put( SvxLanguageItem ( eLang, EE_CHAR_LANGUAGE ) );
+ rEditSet.Put( SvxLanguageItem ( eCjkLang, EE_CHAR_LANGUAGE_CJK ) );
+ rEditSet.Put( SvxLanguageItem ( eCtlLang, EE_CHAR_LANGUAGE_CTL ) );
+ rEditSet.Put( SfxBoolItem ( EE_PARA_HYPHENATE, bHyphenate ) );
+ rEditSet.Put( SvxFrameDirectionItem( eDirection, EE_PARA_WRITINGDIR ) );
+
+ // #111216# Script spacing is always off.
+ // The cell attribute isn't used here as long as there is no UI to set it
+ // (don't evaluate attributes that can't be changed).
+ // If a locale-dependent default is needed, it has to go into the cell
+ // style, like the fonts.
+ rEditSet.Put( SvxScriptSpaceItem( FALSE, EE_PARA_ASIANCJKSPACING ) );
+}
+
+void ScPatternAttr::FillEditItemSet( SfxItemSet* pEditSet, const SfxItemSet* pCondSet ) const
+{
+ if( pEditSet )
+ FillToEditItemSet( *pEditSet, GetItemSet(), pCondSet );
+}
+
+
+void ScPatternAttr::GetFromEditItemSet( SfxItemSet& rDestSet, const SfxItemSet& rEditSet )
+{
+ const SfxPoolItem* pItem;
+
+ if (rEditSet.GetItemState(EE_CHAR_COLOR,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxColorItem(ATTR_FONT_COLOR) = *(const SvxColorItem*)pItem );
+
+ if (rEditSet.GetItemState(EE_CHAR_FONTINFO,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontItem(ATTR_FONT) = *(const SvxFontItem*)pItem );
+ if (rEditSet.GetItemState(EE_CHAR_FONTINFO_CJK,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontItem(ATTR_CJK_FONT) = *(const SvxFontItem*)pItem );
+ if (rEditSet.GetItemState(EE_CHAR_FONTINFO_CTL,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontItem(ATTR_CTL_FONT) = *(const SvxFontItem*)pItem );
+
+ if (rEditSet.GetItemState(EE_CHAR_FONTHEIGHT,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontHeightItem( HMMToTwips( ((const SvxFontHeightItem*)pItem)->GetHeight() ),
+ 100, ATTR_FONT_HEIGHT ) );
+ if (rEditSet.GetItemState(EE_CHAR_FONTHEIGHT_CJK,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontHeightItem( HMMToTwips( ((const SvxFontHeightItem*)pItem)->GetHeight() ),
+ 100, ATTR_CJK_FONT_HEIGHT ) );
+ if (rEditSet.GetItemState(EE_CHAR_FONTHEIGHT_CTL,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxFontHeightItem( HMMToTwips( ((const SvxFontHeightItem*)pItem)->GetHeight() ),
+ 100, ATTR_CTL_FONT_HEIGHT ) );
+
+ if (rEditSet.GetItemState(EE_CHAR_WEIGHT,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxWeightItem( (FontWeight)((const SvxWeightItem*)pItem)->GetValue(),
+ ATTR_FONT_WEIGHT) );
+ if (rEditSet.GetItemState(EE_CHAR_WEIGHT_CJK,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxWeightItem( (FontWeight)((const SvxWeightItem*)pItem)->GetValue(),
+ ATTR_CJK_FONT_WEIGHT) );
+ if (rEditSet.GetItemState(EE_CHAR_WEIGHT_CTL,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxWeightItem( (FontWeight)((const SvxWeightItem*)pItem)->GetValue(),
+ ATTR_CTL_FONT_WEIGHT) );
+
+ // SvxTextLineItem contains enum and color
+ if (rEditSet.GetItemState(EE_CHAR_UNDERLINE,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxUnderlineItem(UNDERLINE_NONE,ATTR_FONT_UNDERLINE) = *(const SvxUnderlineItem*)pItem );
+ if (rEditSet.GetItemState(EE_CHAR_OVERLINE,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxOverlineItem(UNDERLINE_NONE,ATTR_FONT_OVERLINE) = *(const SvxOverlineItem*)pItem );
+ if (rEditSet.GetItemState(EE_CHAR_WLM,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxWordLineModeItem( ((const SvxWordLineModeItem*)pItem)->GetValue(),
+ ATTR_FONT_WORDLINE) );
+
+ if (rEditSet.GetItemState(EE_CHAR_STRIKEOUT,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxCrossedOutItem( (FontStrikeout)((const SvxCrossedOutItem*)pItem)->GetValue(),
+ ATTR_FONT_CROSSEDOUT) );
+
+ if (rEditSet.GetItemState(EE_CHAR_ITALIC,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxPostureItem( (FontItalic)((const SvxPostureItem*)pItem)->GetValue(),
+ ATTR_FONT_POSTURE) );
+ if (rEditSet.GetItemState(EE_CHAR_ITALIC_CJK,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxPostureItem( (FontItalic)((const SvxPostureItem*)pItem)->GetValue(),
+ ATTR_CJK_FONT_POSTURE) );
+ if (rEditSet.GetItemState(EE_CHAR_ITALIC_CTL,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxPostureItem( (FontItalic)((const SvxPostureItem*)pItem)->GetValue(),
+ ATTR_CTL_FONT_POSTURE) );
+
+ if (rEditSet.GetItemState(EE_CHAR_OUTLINE,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxContourItem( ((const SvxContourItem*)pItem)->GetValue(),
+ ATTR_FONT_CONTOUR) );
+ if (rEditSet.GetItemState(EE_CHAR_SHADOW,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxShadowedItem( ((const SvxShadowedItem*)pItem)->GetValue(),
+ ATTR_FONT_SHADOWED) );
+ if (rEditSet.GetItemState(EE_CHAR_EMPHASISMARK,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxEmphasisMarkItem( ((const SvxEmphasisMarkItem*)pItem)->GetEmphasisMark(),
+ ATTR_FONT_EMPHASISMARK) );
+ if (rEditSet.GetItemState(EE_CHAR_RELIEF,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxCharReliefItem( (FontRelief)((const SvxCharReliefItem*)pItem)->GetValue(),
+ ATTR_FONT_RELIEF) );
+
+ if (rEditSet.GetItemState(EE_CHAR_LANGUAGE,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxLanguageItem(static_cast<const SvxLanguageItem*>(pItem)->GetValue(), ATTR_FONT_LANGUAGE) );
+ if (rEditSet.GetItemState(EE_CHAR_LANGUAGE_CJK,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxLanguageItem(static_cast<const SvxLanguageItem*>(pItem)->GetValue(), ATTR_CJK_FONT_LANGUAGE) );
+ if (rEditSet.GetItemState(EE_CHAR_LANGUAGE_CTL,TRUE,&pItem) == SFX_ITEM_SET)
+ rDestSet.Put( SvxLanguageItem(static_cast<const SvxLanguageItem*>(pItem)->GetValue(), ATTR_CTL_FONT_LANGUAGE) );
+
+ if (rEditSet.GetItemState(EE_PARA_JUST,TRUE,&pItem) == SFX_ITEM_SET)
+ {
+ SvxCellHorJustify eVal;
+ switch ( ((const SvxAdjustItem*)pItem)->GetAdjust() )
+ {
+ case SVX_ADJUST_LEFT:
+ // #30154# EditEngine Default ist bei dem GetAttribs() ItemSet
+ // immer gesetzt!
+ // ob links oder rechts entscheiden wir selbst bei Text/Zahl
+ eVal = SVX_HOR_JUSTIFY_STANDARD;
+ break;
+ case SVX_ADJUST_RIGHT:
+ eVal = SVX_HOR_JUSTIFY_RIGHT;
+ break;
+ case SVX_ADJUST_BLOCK:
+ eVal = SVX_HOR_JUSTIFY_BLOCK;
+ break;
+ case SVX_ADJUST_CENTER:
+ eVal = SVX_HOR_JUSTIFY_CENTER;
+ break;
+ case SVX_ADJUST_BLOCKLINE:
+ eVal = SVX_HOR_JUSTIFY_BLOCK;
+ break;
+ case SVX_ADJUST_END:
+ eVal = SVX_HOR_JUSTIFY_RIGHT;
+ break;
+ default:
+ eVal = SVX_HOR_JUSTIFY_STANDARD;
+ }
+ if ( eVal != SVX_HOR_JUSTIFY_STANDARD )
+ rDestSet.Put( SvxHorJustifyItem( eVal, ATTR_HOR_JUSTIFY) );
+ }
+}
+
+void ScPatternAttr::GetFromEditItemSet( const SfxItemSet* pEditSet )
+{
+ if( pEditSet )
+ GetFromEditItemSet( GetItemSet(), *pEditSet );
+}
+
+void ScPatternAttr::FillEditParaItems( SfxItemSet* pEditSet ) const
+{
+ // in GetFromEditItemSet schon dabei, in FillEditItemSet aber nicht
+ // Hor. Ausrichtung Standard wird immer als "links" umgesetzt
+
+ const SfxItemSet& rMySet = GetItemSet();
+
+ SvxCellHorJustify eHorJust = (SvxCellHorJustify)
+ ((const SvxHorJustifyItem&)rMySet.Get(ATTR_HOR_JUSTIFY)).GetValue();
+
+ SvxAdjust eSvxAdjust;
+ switch (eHorJust)
+ {
+ case SVX_HOR_JUSTIFY_RIGHT: eSvxAdjust = SVX_ADJUST_RIGHT; break;
+ case SVX_HOR_JUSTIFY_CENTER: eSvxAdjust = SVX_ADJUST_CENTER; break;
+ case SVX_HOR_JUSTIFY_BLOCK: eSvxAdjust = SVX_ADJUST_BLOCK; break;
+ default: eSvxAdjust = SVX_ADJUST_LEFT; break;
+ }
+ pEditSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
+}
+
+void ScPatternAttr::DeleteUnchanged( const ScPatternAttr* pOldAttrs )
+{
+ SfxItemSet& rThisSet = GetItemSet();
+ const SfxItemSet& rOldSet = pOldAttrs->GetItemSet();
+
+ const SfxPoolItem* pThisItem;
+ const SfxPoolItem* pOldItem;
+
+ for ( USHORT nSubWhich=ATTR_PATTERN_START; nSubWhich<=ATTR_PATTERN_END; nSubWhich++ )
+ {
+ // only items that are set are interesting
+ if ( rThisSet.GetItemState( nSubWhich, FALSE, &pThisItem ) == SFX_ITEM_SET )
+ {
+ SfxItemState eOldState = rOldSet.GetItemState( nSubWhich, TRUE, &pOldItem );
+ if ( eOldState == SFX_ITEM_SET )
+ {
+ // item is set in OldAttrs (or its parent) -> compare pointers
+ if ( pThisItem == pOldItem )
+ rThisSet.ClearItem( nSubWhich );
+ }
+ else if ( eOldState != SFX_ITEM_DONTCARE )
+ {
+ // not set in OldAttrs -> compare item value to default item
+ if ( *pThisItem == rThisSet.GetPool()->GetDefaultItem( nSubWhich ) )
+ rThisSet.ClearItem( nSubWhich );
+ }
+ }
+ }
+}
+
+BOOL ScPatternAttr::HasItemsSet( const USHORT* pWhich ) const
+{
+ const SfxItemSet& rSet = GetItemSet();
+ for (USHORT i=0; pWhich[i]; i++)
+ if ( rSet.GetItemState( pWhich[i], FALSE ) == SFX_ITEM_SET )
+ return TRUE;
+ return FALSE;
+}
+
+void ScPatternAttr::ClearItems( const USHORT* pWhich )
+{
+ SfxItemSet& rSet = GetItemSet();
+ for (USHORT i=0; pWhich[i]; i++)
+ rSet.ClearItem(pWhich[i]);
+}
+
+SfxStyleSheetBase* lcl_CopyStyleToPool
+ (
+ SfxStyleSheetBase* pSrcStyle,
+ SfxStyleSheetBasePool* pSrcPool,
+ SfxStyleSheetBasePool* pDestPool,
+ const SvNumberFormatterIndexTable* pFormatExchangeList
+ )
+{
+ if ( !pSrcStyle || !pDestPool || !pSrcPool )
+ {
+ DBG_ERROR( "CopyStyleToPool: Invalid Arguments :-/" );
+ return NULL;
+ }
+
+ //--------------------------------------------------------
+
+ const String aStrSrcStyle = pSrcStyle->GetName();
+ const SfxStyleFamily eFamily = pSrcStyle->GetFamily();
+ SfxStyleSheetBase* pDestStyle = pDestPool->Find( aStrSrcStyle, eFamily );
+
+ if ( !pDestStyle )
+ {
+ const String aStrParent = pSrcStyle->GetParent();
+ const SfxItemSet& rSrcSet = pSrcStyle->GetItemSet();
+
+ pDestStyle = &pDestPool->Make( aStrSrcStyle, eFamily, SFXSTYLEBIT_USERDEF );
+ SfxItemSet& rDestSet = pDestStyle->GetItemSet();
+ rDestSet.Put( rSrcSet );
+
+ // #b5017505# number format exchange list has to be handled here, too
+ // (only called for cell styles)
+
+ const SfxPoolItem* pSrcItem;
+ if ( pFormatExchangeList &&
+ rSrcSet.GetItemState( ATTR_VALUE_FORMAT, FALSE, &pSrcItem ) == SFX_ITEM_SET )
+ {
+ ULONG nOldFormat = static_cast<const SfxUInt32Item*>(pSrcItem)->GetValue();
+ sal_uInt32* pNewFormat = static_cast<sal_uInt32*>(pFormatExchangeList->Get( nOldFormat ));
+ if (pNewFormat)
+ rDestSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, *pNewFormat ) );
+ }
+
+ // ggF. abgeleitete Styles erzeugen, wenn nicht vorhanden:
+
+ if ( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) != aStrParent &&
+ aStrSrcStyle != aStrParent &&
+ !pDestPool->Find( aStrParent, eFamily ) )
+ {
+ lcl_CopyStyleToPool( pSrcPool->Find( aStrParent, eFamily ),
+ pSrcPool, pDestPool, pFormatExchangeList );
+ }
+
+ pDestStyle->SetParent( aStrParent );
+ }
+
+ return pDestStyle;
+}
+
+ScPatternAttr* ScPatternAttr::PutInPool( ScDocument* pDestDoc, ScDocument* pSrcDoc ) const
+{
+ const SfxItemSet* pSrcSet = &GetItemSet();
+
+ ScPatternAttr* pDestPattern = new ScPatternAttr(pDestDoc->GetPool());
+ SfxItemSet* pDestSet = &pDestPattern->GetItemSet();
+
+ // Zellformatvorlage in anderes Dokument kopieren:
+
+ if ( pDestDoc != pSrcDoc )
+ {
+ DBG_ASSERT( pStyle, "Missing Pattern-Style! :-/" );
+
+ // wenn Vorlage im DestDoc vorhanden, dieses benutzen, sonst Style
+ // mit Parent-Vorlagen kopieren/ggF. erzeugen und dem DestDoc hinzufuegen
+
+ SfxStyleSheetBase* pStyleCpy = lcl_CopyStyleToPool( pStyle,
+ pSrcDoc->GetStyleSheetPool(),
+ pDestDoc->GetStyleSheetPool(),
+ pDestDoc->GetFormatExchangeList() );
+
+ pDestPattern->SetStyleSheet( (ScStyleSheet*)pStyleCpy );
+ }
+
+ for ( USHORT nAttrId = ATTR_PATTERN_START; nAttrId <= ATTR_PATTERN_END; nAttrId++ )
+ {
+ const SfxPoolItem* pSrcItem;
+ SfxItemState eItemState = pSrcSet->GetItemState( nAttrId, FALSE, &pSrcItem );
+ if (eItemState==SFX_ITEM_ON)
+ {
+ SfxPoolItem* pNewItem = NULL;
+
+ if ( nAttrId == ATTR_CONDITIONAL )
+ {
+ // Bedingte Formate ins neue Dokument kopieren
+
+ ULONG nNewIndex = 0;
+ ScConditionalFormatList* pSrcList = pSrcDoc->GetCondFormList();
+ if ( pSrcList )
+ {
+ ULONG nOldIndex = ((const SfxUInt32Item*)pSrcItem)->GetValue();
+ const ScConditionalFormat* pOldData = pSrcList->GetFormat( nOldIndex );
+ if ( pOldData )
+ {
+ nNewIndex = pDestDoc->AddCondFormat( *pOldData );
+
+ // zugehoerige Styles auch mitkopieren
+ //! nur wenn Format bei Add neu angelegt
+
+ ScStyleSheetPool* pSrcSPool = pSrcDoc->GetStyleSheetPool();
+ ScStyleSheetPool* pDestSPool = pDestDoc->GetStyleSheetPool();
+ const SvNumberFormatterIndexTable* pFormatExchangeList = pDestDoc->GetFormatExchangeList();
+ USHORT nStlCnt = pOldData->Count();
+ for (USHORT i=0; i<nStlCnt; i++)
+ {
+ String aName = pOldData->GetEntry(i)->GetStyle();
+ SfxStyleSheetBase* pSrcStl =
+ pSrcDoc->GetStyleSheetPool()->Find(aName, SFX_STYLE_FAMILY_PARA);
+ lcl_CopyStyleToPool( pSrcStl, pSrcSPool, pDestSPool, pFormatExchangeList );
+ }
+ }
+ }
+ pNewItem = new SfxUInt32Item( ATTR_CONDITIONAL, nNewIndex );
+ }
+ else if ( nAttrId == ATTR_VALIDDATA )
+ {
+ // Gueltigkeit ins neue Dokument kopieren
+
+ ULONG nNewIndex = 0;
+ ScValidationDataList* pSrcList = pSrcDoc->GetValidationList();
+ if ( pSrcList )
+ {
+ ULONG nOldIndex = ((const SfxUInt32Item*)pSrcItem)->GetValue();
+ const ScValidationData* pOldData = pSrcList->GetData( nOldIndex );
+ if ( pOldData )
+ nNewIndex = pDestDoc->AddValidationEntry( *pOldData );
+ }
+ pNewItem = new SfxUInt32Item( ATTR_VALIDDATA, nNewIndex );
+ }
+ else if ( nAttrId == ATTR_VALUE_FORMAT && pDestDoc->GetFormatExchangeList() )
+ {
+ // Zahlformate nach Exchange-Liste
+
+ ULONG nOldFormat = ((const SfxUInt32Item*)pSrcItem)->GetValue();
+ sal_uInt32* pNewFormat = static_cast<sal_uInt32*>(pDestDoc->GetFormatExchangeList()->Get(nOldFormat));
+ if (pNewFormat)
+ pNewItem = new SfxUInt32Item( ATTR_VALUE_FORMAT, (UINT32) (*pNewFormat) );
+ }
+
+ if ( pNewItem )
+ {
+ pDestSet->Put(*pNewItem);
+ delete pNewItem;
+ }
+ else
+ pDestSet->Put(*pSrcItem);
+ }
+ }
+
+ ScPatternAttr* pPatternAttr =
+ (ScPatternAttr*) &pDestDoc->GetPool()->Put(*pDestPattern);
+ delete pDestPattern;
+ return pPatternAttr;
+}
+
+BOOL ScPatternAttr::IsVisible() const
+{
+ const SfxItemSet& rSet = GetItemSet();
+
+ const SfxPoolItem* pItem;
+ SfxItemState eState;
+
+ eState = rSet.GetItemState( ATTR_BACKGROUND, TRUE, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ if ( ((const SvxBrushItem*)pItem)->GetColor().GetColor() != COL_TRANSPARENT )
+ return TRUE;
+
+ eState = rSet.GetItemState( ATTR_BORDER, TRUE, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ {
+ const SvxBoxItem* pBoxItem = (SvxBoxItem*) pItem;
+ if ( pBoxItem->GetTop() || pBoxItem->GetBottom() ||
+ pBoxItem->GetLeft() || pBoxItem->GetRight() )
+ return TRUE;
+ }
+
+ eState = rSet.GetItemState( ATTR_BORDER_TLBR, TRUE, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ if( static_cast< const SvxLineItem* >( pItem )->GetLine() )
+ return TRUE;
+
+ eState = rSet.GetItemState( ATTR_BORDER_BLTR, TRUE, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ if( static_cast< const SvxLineItem* >( pItem )->GetLine() )
+ return TRUE;
+
+ eState = rSet.GetItemState( ATTR_SHADOW, TRUE, &pItem );
+ if ( eState == SFX_ITEM_SET )
+ if ( ((const SvxShadowItem*)pItem)->GetLocation() != SVX_SHADOW_NONE )
+ return TRUE;
+
+ return FALSE;
+}
+
+inline BOOL OneEqual( const SfxItemSet& rSet1, const SfxItemSet& rSet2, USHORT nId )
+{
+ const SfxPoolItem* pItem1 = &rSet1.Get(nId);
+ const SfxPoolItem* pItem2 = &rSet2.Get(nId);
+ return ( pItem1 == pItem2 || *pItem1 == *pItem2 );
+}
+
+BOOL ScPatternAttr::IsVisibleEqual( const ScPatternAttr& rOther ) const
+{
+ const SfxItemSet& rThisSet = GetItemSet();
+ const SfxItemSet& rOtherSet = rOther.GetItemSet();
+
+ return OneEqual( rThisSet, rOtherSet, ATTR_BACKGROUND ) &&
+ OneEqual( rThisSet, rOtherSet, ATTR_BORDER ) &&
+ OneEqual( rThisSet, rOtherSet, ATTR_BORDER_TLBR ) &&
+ OneEqual( rThisSet, rOtherSet, ATTR_BORDER_BLTR ) &&
+ OneEqual( rThisSet, rOtherSet, ATTR_SHADOW );
+
+ //! auch hier nur wirklich sichtbare Werte testen !!!
+}
+
+const String* ScPatternAttr::GetStyleName() const
+{
+ return pName ? pName : ( pStyle ? &pStyle->GetName() : NULL );
+}
+
+
+void ScPatternAttr::SetStyleSheet( ScStyleSheet* pNewStyle )
+{
+ if (pNewStyle)
+ {
+ SfxItemSet& rPatternSet = GetItemSet();
+ const SfxItemSet& rStyleSet = pNewStyle->GetItemSet();
+
+ for (USHORT i=ATTR_PATTERN_START; i<=ATTR_PATTERN_END; i++)
+ {
+ if (rStyleSet.GetItemState(i, TRUE) == SFX_ITEM_SET)
+ rPatternSet.ClearItem(i);
+ }
+ rPatternSet.SetParent(&pNewStyle->GetItemSet());
+ pStyle = pNewStyle;
+ DELETEZ( pName );
+ }
+ else
+ {
+ DBG_ERROR( "ScPatternAttr::SetStyleSheet( NULL ) :-|" );
+ GetItemSet().SetParent(NULL);
+ pStyle = NULL;
+ }
+}
+
+void ScPatternAttr::UpdateStyleSheet()
+{
+ if (pName)
+ {
+ pStyle = (ScStyleSheet*)pDoc->GetStyleSheetPool()->Find(*pName, SFX_STYLE_FAMILY_PARA);
+
+ // wenn Style nicht gefunden, Standard nehmen,
+ // damit keine leere Anzeige im Toolbox-Controller
+ //! es wird vorausgesetzt, dass "Standard" immer der erste Eintrag ist!
+ if (!pStyle)
+ {
+ SfxStyleSheetIterator* pIter = pDoc->GetStyleSheetPool()->CreateIterator(
+ SFX_STYLE_FAMILY_PARA, SFXSTYLEBIT_ALL );
+ pStyle = (ScStyleSheet*)pIter->First();
+ }
+
+ if (pStyle)
+ {
+ GetItemSet().SetParent(&pStyle->GetItemSet());
+ DELETEZ( pName );
+ }
+ }
+ else
+ pStyle = NULL;
+}
+
+void ScPatternAttr::StyleToName()
+{
+ // Style wurde geloescht, Namen merken:
+
+ if ( pStyle )
+ {
+ if ( pName )
+ *pName = pStyle->GetName();
+ else
+ pName = new String( pStyle->GetName() );
+
+ pStyle = NULL;
+ GetItemSet().SetParent( NULL );
+ }
+}
+
+BOOL ScPatternAttr::IsSymbolFont() const
+{
+ const SfxPoolItem* pItem;
+ if( GetItemSet().GetItemState( ATTR_FONT, TRUE, &pItem ) == SFX_ITEM_SET )
+ return BOOL( ((const SvxFontItem*) pItem)->GetCharSet()
+ == RTL_TEXTENCODING_SYMBOL );
+ else
+ return FALSE;
+}
+
+//UNUSED2008-05 FontToSubsFontConverter ScPatternAttr::GetSubsFontConverter( ULONG nFlags ) const
+//UNUSED2008-05 {
+//UNUSED2008-05 const SfxPoolItem* pItem;
+//UNUSED2008-05 if( GetItemSet().GetItemState( ATTR_FONT, TRUE, &pItem ) == SFX_ITEM_SET )
+//UNUSED2008-05 return CreateFontToSubsFontConverter(
+//UNUSED2008-05 ((const SvxFontItem*) pItem)->GetFamilyName(), nFlags );
+//UNUSED2008-05 else
+//UNUSED2008-05 return 0;
+//UNUSED2008-05 }
+
+
+ULONG ScPatternAttr::GetNumberFormat( SvNumberFormatter* pFormatter ) const
+{
+ ULONG nFormat =
+ ((SfxUInt32Item*)&GetItemSet().Get( ATTR_VALUE_FORMAT ))->GetValue();
+ LanguageType eLang =
+ ((SvxLanguageItem*)&GetItemSet().Get( ATTR_LANGUAGE_FORMAT ))->GetLanguage();
+ if ( nFormat < SV_COUNTRY_LANGUAGE_OFFSET && eLang == LANGUAGE_SYSTEM )
+ ; // es bleibt wie es ist
+ else if ( pFormatter )
+ nFormat = pFormatter->GetFormatForLanguageIfBuiltIn( nFormat, eLang );
+ return nFormat;
+}
+
+// dasselbe, wenn bedingte Formatierung im Spiel ist:
+
+ULONG ScPatternAttr::GetNumberFormat( SvNumberFormatter* pFormatter,
+ const SfxItemSet* pCondSet ) const
+{
+ DBG_ASSERT(pFormatter,"GetNumberFormat ohne Formatter");
+
+ const SfxPoolItem* pFormItem;
+ if ( !pCondSet || pCondSet->GetItemState(ATTR_VALUE_FORMAT,TRUE,&pFormItem) != SFX_ITEM_SET )
+ pFormItem = &GetItemSet().Get(ATTR_VALUE_FORMAT);
+
+ const SfxPoolItem* pLangItem;
+ if ( !pCondSet || pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT,TRUE,&pLangItem) != SFX_ITEM_SET )
+ pLangItem = &GetItemSet().Get(ATTR_LANGUAGE_FORMAT);
+
+ return pFormatter->GetFormatForLanguageIfBuiltIn(
+ ((SfxUInt32Item*)pFormItem)->GetValue(),
+ ((SvxLanguageItem*)pLangItem)->GetLanguage() );
+}
+
+const SfxPoolItem& ScPatternAttr::GetItem( USHORT nWhich, const SfxItemSet& rItemSet, const SfxItemSet* pCondSet )
+{
+ const SfxPoolItem* pCondItem;
+ if ( pCondSet && pCondSet->GetItemState( nWhich, TRUE, &pCondItem ) == SFX_ITEM_SET )
+ return *pCondItem;
+ return rItemSet.Get(nWhich);
+}
+
+const SfxPoolItem& ScPatternAttr::GetItem( USHORT nSubWhich, const SfxItemSet* pCondSet ) const
+{
+ return GetItem( nSubWhich, GetItemSet(), pCondSet );
+}
+
+// GetRotateVal testet vorher ATTR_ORIENTATION
+
+long ScPatternAttr::GetRotateVal( const SfxItemSet* pCondSet ) const
+{
+ long nAttrRotate = 0;
+ if ( GetCellOrientation() == SVX_ORIENTATION_STANDARD )
+ {
+ BOOL bRepeat = ( static_cast<const SvxHorJustifyItem&>(GetItem(ATTR_HOR_JUSTIFY, pCondSet)).
+ GetValue() == SVX_HOR_JUSTIFY_REPEAT );
+ // ignore orientation/rotation if "repeat" is active
+ if ( !bRepeat )
+ nAttrRotate = ((const SfxInt32Item&)GetItem( ATTR_ROTATE_VALUE, pCondSet )).GetValue();
+ }
+ return nAttrRotate;
+}
+
+BYTE ScPatternAttr::GetRotateDir( const SfxItemSet* pCondSet ) const
+{
+ BYTE nRet = SC_ROTDIR_NONE;
+
+ long nAttrRotate = GetRotateVal( pCondSet );
+ if ( nAttrRotate )
+ {
+ SvxRotateMode eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
+ GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
+
+ if ( eRotMode == SVX_ROTATE_MODE_STANDARD || nAttrRotate == 18000 )
+ nRet = SC_ROTDIR_STANDARD;
+ else if ( eRotMode == SVX_ROTATE_MODE_CENTER )
+ nRet = SC_ROTDIR_CENTER;
+ else if ( eRotMode == SVX_ROTATE_MODE_TOP || eRotMode == SVX_ROTATE_MODE_BOTTOM )
+ {
+ long nRot180 = nAttrRotate % 18000; // 1/100 Grad
+ if ( nRot180 == 9000 )
+ nRet = SC_ROTDIR_CENTER;
+ else if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nRot180 < 9000 ) ||
+ ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nRot180 > 9000 ) )
+ nRet = SC_ROTDIR_LEFT;
+ else
+ nRet = SC_ROTDIR_RIGHT;
+ }
+ }
+
+ return nRet;
+}
+
+
+
+
diff --git a/sc/source/core/data/pivot.cxx b/sc/source/core/data/pivot.cxx
new file mode 100644
index 000000000000..30bacf79989a
--- /dev/null
+++ b/sc/source/core/data/pivot.cxx
@@ -0,0 +1,2028 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: pivot.cxx,v $
+ * $Revision: 1.13 $
+ *
+ * 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"
+
+
+
+// -----------------------------------------------------------------------
+#if OLD_PIVOT_IMPLEMENTATION
+#ifdef _MSC_VER
+#pragma optimize("",off)
+#endif
+
+// INCLUDE ---------------------------------------------------------------
+
+#include <svtools/zforlist.hxx>
+#include <tools/solar.h>
+
+#include "globstr.hrc"
+#include "global.hxx"
+#include "subtotal.hxx"
+#include "scitems.hxx"
+#include "attrib.hxx"
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "document.hxx"
+#include "userlist.hxx"
+#include "pivot.hxx"
+#include "cell.hxx"
+#include "rechead.hxx"
+#include "compiler.hxx" // fuer errNoValue
+#include "progress.hxx"
+
+#include <string.h>
+#include <math.h>
+
+// STATIC DATA -----------------------------------------------------------
+
+//! bei Gelegenheit...
+
+static short nStaticStrRefCount = 0;
+static String* pLabel[PIVOT_MAXFUNC+1]; // incl. "auto"
+static String* pLabelTotal;
+static String* pLabelData;
+
+static SCSIZE nDataMult = 1;
+
+#define nFirstLine 2
+
+static const USHORT nFuncMaskArr[PIVOT_MAXFUNC+1] =
+ { PIVOT_FUNC_SUM,
+ PIVOT_FUNC_COUNT,
+ PIVOT_FUNC_AVERAGE,
+ PIVOT_FUNC_MAX,
+ PIVOT_FUNC_MIN,
+ PIVOT_FUNC_PRODUCT,
+ PIVOT_FUNC_COUNT_NUM,
+ PIVOT_FUNC_STD_DEV,
+ PIVOT_FUNC_STD_DEVP,
+ PIVOT_FUNC_STD_VAR,
+ PIVOT_FUNC_STD_VARP,
+ PIVOT_FUNC_AUTO }; // automatisch
+
+// -----------------------------------------------------------------------
+
+// 1 Filter-Knopf
+// 2 Feldnamen links
+// 3 "Daten" links
+// 4 Feldnamen oben
+// 5 "Daten" oben
+// 6 einzelne "Gesamt" oben rechts
+// 7 "Gesamt" oben rechts
+// 8 einzelne "Gesamt" unten links
+// 9 "Gesamt" unten links
+// 10 innere Kategorie links
+// 11 Teilergebnis Label einzeln links
+// 12 Teilergebnis Label gesamt links
+// 13 letzte Kategorie links
+// 14 innere Kategorie oben
+// 15 Teilergebnis Label einzeln oben
+// 16 Teilergebnis Label gesamt oben
+// 17 letzte Kategorie oben
+// 18 Werte innen
+// 19 Werte in Teilergebnisspalte
+// 20 Werte in Gesamt-Spalte
+// 21 Werte in einzelnen Gesamt-Spalten
+// 22 Werte in Ergebnis-Zeile Teilergebnis oder Gesamt
+// 23 Kreuzung von Spalte/Zeile (Teilergebnis-Spalte)
+// 24 Kreuzung von Spalte/Zeile (Gesamt-Spalte)
+// 25 wie 24 bei einzelnen "Gesamt"
+
+SCSIZE lcl_MaskToIndex( USHORT nFuncMask )
+{
+ SCSIZE i;
+ for (i=0; i<=PIVOT_MAXFUNC; i++)
+ if (nFuncMask == nFuncMaskArr[i])
+ return i;
+
+ DBG_ERROR("Falsche Maske in MaskToIndex");
+ return 0;
+}
+
+BOOL lcl_IsEmptyLine( ScDocument* pDoc, const ScAddress& rPos, SCCOL nCol2 )
+{
+ //! ans Document verschieben !!!
+
+ ScAddress aAdr( rPos );
+ for (SCCOL nCol=aAdr.Col(); nCol<=nCol2; nCol++)
+ {
+ aAdr.SetCol( nCol );
+ if ( pDoc->GetCell( aAdr ) )
+ return FALSE;
+ }
+ return TRUE;
+}
+
+ScPivot::ScPivot(ScDocument* pDocument) :
+ pDoc (pDocument),
+ aQuery (),
+ bHasHeader (FALSE),
+ bIgnoreEmpty (FALSE),
+ bDetectCat (FALSE),
+ bMakeTotalCol (TRUE),
+ bMakeTotalRow (TRUE),
+ nColNameCount (0),
+ pColNames (NULL),
+ nSrcCol1 (0),
+ nSrcRow1 (0),
+ nSrcCol2 (0),
+ nSrcRow2 (0),
+ nSrcTab (0),
+ nDestCol1 (0),
+ nDestRow1 (0),
+ nDestCol2 (0),
+ nDestRow2 (0),
+ nDestTab (0),
+ nDataStartCol (0),
+ nDataStartRow (0),
+ nColCount (0),
+ nRowCount (0),
+ nDataCount (0),
+ bValidArea (FALSE),
+ bDataAtCol (FALSE)
+{
+ for (SCSIZE i=0; i<PIVOT_MAXFIELD; i++)
+ {
+ pColList[i] = new PivotScStrCollection();
+ pRowList[i] = new PivotScStrCollection();
+ }
+ pDataList = pColList[0];
+ ppDataArr = NULL;
+ nDataColCount = 0;
+ nDataRowCount = 0;
+ nRecCount = 0;
+ pColRef = NULL;
+
+ // Initialisierung der statischen Strings, wenn noetig
+ nStaticStrRefCount += 1;
+ if ( nStaticStrRefCount < 2 )
+ {
+ pLabelTotal = new String( ScGlobal::GetRscString(STR_PIVOT_TOTAL) );
+ pLabelData = new String( ScGlobal::GetRscString(STR_PIVOT_DATA) );
+
+ for (SCSIZE i=0; i<=PIVOT_MAXFUNC; i++ ) // incl. "auto"
+ pLabel[i] = new String; // kein Leerzeichen
+
+ *pLabel[ 0] = ScGlobal::GetRscString(STR_FUN_TEXT_SUM);
+ *pLabel[ 1] = ScGlobal::GetRscString(STR_FUN_TEXT_COUNT);
+ *pLabel[ 2] = ScGlobal::GetRscString(STR_FUN_TEXT_AVG);
+ *pLabel[ 3] = ScGlobal::GetRscString(STR_FUN_TEXT_MAX);
+ *pLabel[ 4] = ScGlobal::GetRscString(STR_FUN_TEXT_MIN);
+ *pLabel[ 5] = ScGlobal::GetRscString(STR_FUN_TEXT_PRODUCT);
+ *pLabel[ 6] = ScGlobal::GetRscString(STR_FUN_TEXT_COUNT); // Count2
+ *pLabel[ 7] = ScGlobal::GetRscString(STR_FUN_TEXT_STDDEV);
+ *pLabel[ 8] = ScGlobal::GetRscString(STR_FUN_TEXT_STDDEV); // Stddev2
+ *pLabel[ 9] = ScGlobal::GetRscString(STR_FUN_TEXT_VAR);
+ *pLabel[10] = ScGlobal::GetRscString(STR_FUN_TEXT_VAR); // Var2
+ *pLabel[11] = ScGlobal::GetRscString(STR_TABLE_ERGEBNIS);
+ }
+}
+
+ScPivot::ScPivot(const ScPivot& rPivot):
+ ScDataObject(),
+ pDoc (rPivot.pDoc),
+ aQuery (rPivot.aQuery),
+ bHasHeader (rPivot.bHasHeader),
+ bIgnoreEmpty (rPivot.bIgnoreEmpty),
+ bDetectCat (rPivot.bDetectCat),
+ bMakeTotalCol (rPivot.bMakeTotalCol),
+ bMakeTotalRow (rPivot.bMakeTotalRow),
+ aName (rPivot.aName),
+ aTag (rPivot.aTag),
+ nColNameCount (0),
+ pColNames (NULL),
+ nSrcCol1 (rPivot.nSrcCol1),
+ nSrcRow1 (rPivot.nSrcRow1),
+ nSrcCol2 (rPivot.nSrcCol2),
+ nSrcRow2 (rPivot.nSrcRow2),
+ nSrcTab (rPivot.nSrcTab),
+ nDestCol1 (rPivot.nDestCol1),
+ nDestRow1 (rPivot.nDestRow1),
+ nDestCol2 (rPivot.nDestCol2),
+ nDestRow2 (rPivot.nDestRow2),
+ nDestTab (rPivot.nDestTab),
+ nDataStartCol (0),
+ nDataStartRow (0),
+ nColCount (0),
+ nRowCount (0),
+ nDataCount (0),
+ bValidArea (FALSE),
+ bDataAtCol (FALSE)
+{
+ if (rPivot.nColNameCount>0 && rPivot.pColNames)
+ {
+ nColNameCount = rPivot.nColNameCount;
+ pColNames = new String[nColNameCount];
+ for (SCSIZE nCol=0; nCol<nColNameCount; nCol++)
+ pColNames[nCol] = rPivot.pColNames[nCol];
+ }
+
+ for (SCSIZE i=0; i<PIVOT_MAXFIELD; i++)
+ {
+ pColList[i] = new PivotScStrCollection();
+ pRowList[i] = new PivotScStrCollection();
+ }
+ pDataList = pColList[0];
+ ppDataArr = NULL;
+ nRecCount = 0;
+ pColRef = NULL;
+
+ SetColFields( rPivot.aColArr, rPivot.nColCount );
+ SetRowFields( rPivot.aRowArr, rPivot.nRowCount );
+ SetDataFields( rPivot.aDataArr, rPivot.nDataCount );
+
+ nStaticStrRefCount += 1;
+}
+
+ScPivot::~ScPivot()
+{
+ for (SCSIZE i=0; i<PIVOT_MAXFIELD; i++)
+ {
+ delete pColList[i];
+ delete pRowList[i];
+ }
+ if (ppDataArr)
+ {
+ for (SCSIZE j=0; j<nDataRowCount; j++)
+ delete[] ppDataArr[j];
+ delete[] ppDataArr;
+ ppDataArr = NULL;
+ }
+ delete[] pColRef;
+
+ delete[] pColNames;
+
+ // statische Strings ggF. wieder abraeumen
+ nStaticStrRefCount -= 1;
+ if ( nStaticStrRefCount == 0 )
+ {
+ delete pLabelTotal;
+ delete pLabelData;
+
+ for ( SCSIZE k=0; k<=PIVOT_MAXFUNC; k++ ) // incl. "auto"
+ delete pLabel[k];
+ }
+}
+
+ScPivot* ScPivot::CreateNew() const
+{
+ ScPivot* pNewPivot = new ScPivot( pDoc );
+
+ pNewPivot->SetQuery(aQuery);
+ pNewPivot->SetHeader(bHasHeader);
+ pNewPivot->SetIgnoreEmpty(bIgnoreEmpty);
+ pNewPivot->SetDetectCat(bDetectCat);
+ pNewPivot->SetMakeTotalCol(bMakeTotalCol);
+ pNewPivot->SetMakeTotalRow(bMakeTotalRow);
+
+ pNewPivot->SetSrcArea( nSrcCol1, nSrcRow1, nSrcCol2, nSrcRow2, nSrcTab );
+ pNewPivot->SetDestPos( nDestCol1, nDestRow1, nDestTab );
+
+ return pNewPivot;
+}
+
+void lcl_LoadFieldArr30( SvStream& /* rStream */, PivotField* /* pField */, USHORT /* nCount */ )
+{
+#if SC_ROWLIMIT_STREAM_ACCESS
+#error address types changed!
+ USHORT i;
+
+ for (i=0; i<nCount; i++)
+ {
+ rStream >> pField[i].nCol
+ >> pField[i].nFuncMask
+ >> pField[i].nFuncCount;
+ }
+#endif
+}
+
+void lcl_LoadFieldArr( SvStream& /* rStream */, PivotField* /* pField */, USHORT /* nCount */ )
+{
+#if SC_ROWLIMIT_STREAM_ACCESS
+#error address types changed!
+ USHORT i;
+
+ for (i=0; i<nCount; i++)
+ {
+ BYTE cData;
+ rStream >> cData;
+ if( cData & 0x0F )
+ rStream.SeekRel( cData & 0x0F );
+ rStream >> pField[i].nCol
+ >> pField[i].nFuncMask
+ >> pField[i].nFuncCount;
+ }
+#endif
+}
+
+void lcl_SaveFieldArr( SvStream& /* rStream */, const PivotField* /* pField */, USHORT /* nCount */ )
+{
+#if SC_ROWLIMIT_STREAM_ACCESS
+#error address types changed!
+ USHORT i;
+
+ for (i=0; i<nCount; i++)
+ {
+ rStream << (BYTE) 0x00
+ << pField[i].nCol
+ << pField[i].nFuncMask
+ << pField[i].nFuncCount;
+ }
+#endif
+}
+
+// nach Load muessen Daten neu berechnet werden !
+
+BOOL ScPivot::Load( SvStream& /* rStream */, ScMultipleReadHeader& rHdr )
+{
+ rHdr.StartEntry();
+#if SC_ROWLIMIT_STREAM_ACCESS
+#error address types changed!
+
+ rStream >> bHasHeader
+
+ >> nSrcCol1
+ >> nSrcRow1
+ >> nSrcCol2
+ >> nSrcRow2
+ >> nSrcTab
+
+ >> nDestCol1
+ >> nDestRow1
+ >> nDestCol2
+ >> nDestRow2
+ >> nDestTab;
+
+ // Arrays immer ueber Set...Fields initalisieren!
+
+ short nCount;
+ PivotFieldArr aFieldArr;
+
+ if( pDoc->GetSrcVersion() >= SC_DATABYTES2 )
+ {
+ rStream >> nCount;
+ lcl_LoadFieldArr( rStream, aFieldArr, nCount );
+ SetColFields(aFieldArr, nCount);
+
+ rStream >> nCount;
+ lcl_LoadFieldArr( rStream, aFieldArr, nCount );
+ SetRowFields(aFieldArr, nCount);
+
+ rStream >> nCount;
+ lcl_LoadFieldArr( rStream, aFieldArr, nCount );
+ SetDataFields(aFieldArr, nCount);
+ }
+ else
+ {
+ rStream >> nCount;
+ lcl_LoadFieldArr30( rStream, aFieldArr, nCount );
+ SetColFields(aFieldArr, nCount);
+
+ rStream >> nCount;
+ lcl_LoadFieldArr30( rStream, aFieldArr, nCount );
+ SetRowFields(aFieldArr, nCount);
+
+ rStream >> nCount;
+ lcl_LoadFieldArr30( rStream, aFieldArr, nCount );
+ SetDataFields(aFieldArr, nCount);
+ }
+
+ aQuery.Load( rStream );
+
+ rStream >> bIgnoreEmpty;
+ rStream >> bDetectCat;
+
+ if (rHdr.BytesLeft())
+ {
+ rStream >> bMakeTotalCol; // ab 355i
+ rStream >> bMakeTotalRow;
+ }
+
+ if (rHdr.BytesLeft()) // ab 500a
+ {
+ rStream.ReadByteString( aName, rStream.GetStreamCharSet() );
+ rStream.ReadByteString( aTag, rStream.GetStreamCharSet() );
+
+ DBG_ASSERT(!pColNames, "Spaltennamen schon gesetzt?");
+ rStream >> nColNameCount;
+ if (nColNameCount)
+ {
+ pColNames = new String[nColNameCount];
+ for (SCCOL nCol=0; nCol<nColNameCount; nCol++)
+ rStream.ReadByteString( pColNames[nCol], rStream.GetStreamCharSet() );
+ }
+ }
+ // sonst wird hinterher aus ScPivotCollection::Load ein Name vergeben
+
+ rHdr.EndEntry();
+#endif
+ return TRUE;
+}
+
+BOOL ScPivot::Store( SvStream& /* rStream */, ScMultipleWriteHeader& rHdr ) const
+{
+ rHdr.StartEntry();
+#if SC_ROWLIMIT_STREAM_ACCESS
+#error address types changed!
+
+ rStream << bHasHeader
+
+ << nSrcCol1
+ << nSrcRow1
+ << nSrcCol2
+ << nSrcRow2
+ << nSrcTab
+
+ << nDestCol1
+ << nDestRow1
+ << nDestCol2
+ << nDestRow2
+ << nDestTab
+
+ << nColCount;
+ lcl_SaveFieldArr( rStream, aColArr, nColCount );
+ rStream << nRowCount;
+ lcl_SaveFieldArr( rStream, aRowArr, nRowCount );
+ rStream << nDataCount;
+ lcl_SaveFieldArr( rStream, aDataArr, nDataCount );
+
+ aQuery.Store( rStream );
+
+ rStream << bIgnoreEmpty;
+ rStream << bDetectCat;
+
+ rStream << bMakeTotalCol; // ab 355i
+ rStream << bMakeTotalRow;
+
+ if( rStream.GetVersion() > SOFFICE_FILEFORMAT_40 ) // Name/Tag/Spalten ab 5.0
+ {
+ rStream.WriteByteString( aName, rStream.GetStreamCharSet() );
+ rStream.WriteByteString( aTag, rStream.GetStreamCharSet() );
+
+ if (!pColNames) ((ScPivot*)this)->nColNameCount = 0; // soll nicht sein
+ rStream << nColNameCount;
+ for (SCCOL nCol=0; nCol<nColNameCount; nCol++)
+ rStream.WriteByteString( pColNames[nCol], rStream.GetStreamCharSet() );
+ }
+
+ rHdr.EndEntry();
+#endif
+ return TRUE;
+}
+
+void ScPivot::SetQuery(const ScQueryParam& rQuery)
+{
+ aQuery = rQuery;
+
+ bValidArea = FALSE;
+}
+
+void ScPivot::GetQuery(ScQueryParam& rQuery) const
+{
+ rQuery = aQuery;
+}
+
+void ScPivot::SetHeader(BOOL bHeader)
+{
+ bHasHeader = bHeader;
+ bValidArea = FALSE;
+}
+
+BOOL ScPivot::GetHeader() const
+{
+ return bHasHeader;
+}
+
+void ScPivot::SetIgnoreEmpty(BOOL bIgnore)
+{
+ bIgnoreEmpty = bIgnore;
+ bValidArea = FALSE;
+}
+
+BOOL ScPivot::GetIgnoreEmpty() const
+{
+ return bIgnoreEmpty;
+}
+
+void ScPivot::SetDetectCat(BOOL bDetect)
+{
+ bDetectCat = bDetect;
+ bValidArea = FALSE;
+}
+
+BOOL ScPivot::GetDetectCat() const
+{
+ return bDetectCat;
+}
+
+void ScPivot::SetMakeTotalCol(BOOL bSet)
+{
+ bMakeTotalCol = bSet;
+ bValidArea = FALSE;
+}
+
+BOOL ScPivot::GetMakeTotalCol() const
+{
+ return bMakeTotalCol;
+}
+
+void ScPivot::SetMakeTotalRow(BOOL bSet)
+{
+ bMakeTotalRow = bSet;
+ bValidArea = FALSE;
+}
+
+BOOL ScPivot::GetMakeTotalRow() const
+{
+ return bMakeTotalRow;
+}
+
+void ScPivot::SetName(const String& rNew)
+{
+ aName = rNew;
+}
+
+const String& ScPivot::GetName() const
+{
+ return aName;
+}
+
+void ScPivot::SetTag(const String& rNew)
+{
+ aTag = rNew;
+}
+
+const String& ScPivot::GetTag() const
+{
+ return aTag;
+}
+
+void ScPivot::SetSrcArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, SCTAB nTab)
+{
+ nSrcCol1 = Min(nCol1, (SCCOL)MAXCOL);
+ nSrcRow1 = Min(nRow1, (SCROW)MAXROW);
+ nSrcCol2 = Min(nCol2, (SCCOL)MAXCOL);
+ nSrcRow2 = Min(nRow2, (SCROW)MAXROW);
+ nSrcTab = nTab;
+ bValidArea = FALSE;
+}
+
+void ScPivot::GetSrcArea(SCCOL& rCol1, SCROW& rRow1, SCCOL& rCol2, SCROW& rRow2, SCTAB& rTab) const
+{
+ rCol1 = nSrcCol1;
+ rRow1 = nSrcRow1;
+ rCol2 = nSrcCol2;
+ rRow2 = nSrcRow2;
+ rTab = nSrcTab;
+}
+
+ScRange ScPivot::GetSrcArea() const
+{
+ return ScRange( nSrcCol1,nSrcRow1,nSrcTab, nSrcCol2,nSrcRow2,nSrcTab );
+}
+
+void ScPivot::SetDestPos(SCCOL nCol, SCROW nRow, SCTAB nTab)
+{
+ nDestCol1 = nCol;
+ nDestRow1 = nRow;
+ nDestTab = nTab;
+ bValidArea = FALSE;
+}
+
+void ScPivot::GetDestArea(SCCOL& rCol1, SCROW& rRow1, SCCOL& rCol2, SCROW& rRow2, SCTAB& rTab) const
+{
+ rCol1 = nDestCol1;
+ rRow1 = nDestRow1;
+ rTab = nDestTab;
+ if (bValidArea)
+ {
+ rCol2 = nDestCol2;
+ rRow2 = nDestRow2;
+ }
+ else
+ {
+ rCol2 = nDestCol1;
+ rRow2 = nDestRow1;
+ }
+}
+
+ScRange ScPivot::GetDestArea() const
+{
+ ScAddress aStart( nDestCol1, nDestRow1, nDestTab );
+ ScAddress aEnd = aStart;
+ if ( bValidArea )
+ aEnd = ScAddress( nDestCol2, nDestRow2, nDestTab );
+ return ScRange( aStart, aEnd );
+}
+
+void ScPivot::MoveSrcArea( SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab )
+{
+ if ( nNewCol != nSrcCol1 || nNewRow != nSrcRow1 || nNewTab != nSrcTab )
+ {
+ SCsCOL nDiffX = nNewCol - (SCsCOL) nSrcCol1;
+ SCsROW nDiffY = nNewRow - (SCsROW) nSrcRow1;
+
+ nSrcTab = nNewTab;
+ nSrcCol1 = sal::static_int_cast<SCCOL>( nSrcCol1 + nDiffX );
+ nSrcCol2 = sal::static_int_cast<SCCOL>( nSrcCol2 + nDiffX );
+ nSrcRow1 = sal::static_int_cast<SCROW>( nSrcRow1 + nDiffY );
+ nSrcRow2 = sal::static_int_cast<SCROW>( nSrcRow2 + nDiffY );
+
+ aQuery.nCol1 = sal::static_int_cast<SCCOL>( aQuery.nCol1 + nDiffX );
+ aQuery.nCol2 = sal::static_int_cast<SCCOL>( aQuery.nCol2 + nDiffX );
+ aQuery.nRow1 = sal::static_int_cast<SCROW>( aQuery.nRow1 + nDiffY );
+ aQuery.nRow2 = sal::static_int_cast<SCROW>( aQuery.nRow2 + nDiffY );
+
+ SCSIZE nEC = aQuery.GetEntryCount();
+ for (SCSIZE i=0; i<nEC; i++)
+ if (aQuery.GetEntry(i).bDoQuery)
+ aQuery.GetEntry(i).nField += nDiffX;
+
+ if (bValidArea)
+ {
+ SCSIZE nC;
+ SCSIZE nR;
+ for (nC=0; nC<nColCount; nC++)
+ if (aColArr[nC].nCol != PIVOT_DATA_FIELD)
+ aColArr[nC].nCol = sal::static_int_cast<SCsCOL>( aColArr[nC].nCol + nDiffX );
+ for (nR=0; nR<nRowCount; nR++)
+ if (aRowArr[nR].nCol != PIVOT_DATA_FIELD)
+ aRowArr[nR].nCol = sal::static_int_cast<SCsCOL>( aRowArr[nR].nCol + nDiffX );
+ for (nC=0; nC<nDataCount; nC++)
+ if (aDataArr[nC].nCol != PIVOT_DATA_FIELD)
+ aDataArr[nC].nCol = sal::static_int_cast<SCsCOL>( aDataArr[nC].nCol + nDiffX );
+ }
+ }
+}
+
+void ScPivot::ExtendSrcArea( SCCOL nNewEndCol, SCROW nNewEndRow )
+{
+ DBG_ASSERT( nNewEndCol >= nSrcCol2 && nNewEndRow >= nSrcRow2, "ExtendSrcArea: zu klein" );
+
+ nSrcCol2 = nNewEndCol;
+ nSrcRow2 = nNewEndRow;
+
+ // alles andere bleibt erhalten
+}
+
+void ScPivot::MoveDestArea( SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab )
+{
+ if ( nNewCol != nDestCol1 || nNewRow != nDestRow1 || nNewTab != nDestTab )
+ {
+ SCsCOL nDiffX = nNewCol - (SCsCOL) nDestCol1;
+ SCsROW nDiffY = nNewRow - (SCsROW) nDestRow1;
+
+ nDestTab = nNewTab;
+ nDestCol1 = sal::static_int_cast<SCCOL>( nDestCol1 + nDiffX );
+ nDestRow1 = sal::static_int_cast<SCROW>( nDestRow1 + nDiffY );
+
+ if (bValidArea)
+ {
+ nDestCol2 = sal::static_int_cast<SCCOL>( nDestCol2 + nDiffX );
+ nDestRow2 = sal::static_int_cast<SCROW>( nDestRow2 + nDiffY );
+
+ nDataStartCol = sal::static_int_cast<SCCOL>( nDataStartCol + nDiffX );
+ nDataStartRow = sal::static_int_cast<SCROW>( nDataStartRow + nDiffY );
+ }
+ }
+}
+
+void ScPivot::SetColFields(const PivotField* pFieldArr, SCSIZE nCount)
+{
+ nColCount = Max(static_cast<SCSIZE>(0), Min(nCount, PIVOT_MAXFIELD));
+ for (SCSIZE i = 0; i < nColCount; i++)
+ {
+ aColArr[i] = pFieldArr[i];
+ aColArr[i].nFuncCount = 0;
+ if (aColArr[i].nCol == PIVOT_DATA_FIELD)
+ {
+ aColArr[i].nFuncMask = PIVOT_FUNC_NONE;
+ pDataList = pColList[i];
+ bDataAtCol = TRUE;
+ }
+ else
+ {
+ for (SCsCOL j=0; j<=PIVOT_MAXFUNC; j++) // incl. "auto"
+ if (aColArr[i].nFuncMask & nFuncMaskArr[j])
+ aColArr[i].nFuncCount++;
+ }
+ }
+ bValidArea = FALSE;
+}
+
+void ScPivot::GetColFields(PivotField* pFieldArr, SCSIZE& rCount) const
+{
+ for (SCSIZE i=0; i<nColCount; i++)
+ pFieldArr[i] = aColArr[i];
+ rCount = nColCount;
+}
+
+void ScPivot::SetRowFields(const PivotField* pFieldArr, SCSIZE nCount)
+{
+ nRowCount = Max(static_cast<SCSIZE>(0), Min(nCount, PIVOT_MAXFIELD));
+ for (SCSIZE i = 0; i < nRowCount; i++)
+ {
+ aRowArr[i] = pFieldArr[i];
+ aRowArr[i].nFuncCount = 0;
+ if (aRowArr[i].nCol == PIVOT_DATA_FIELD)
+ {
+ aRowArr[i].nFuncMask = PIVOT_FUNC_NONE;
+ pDataList = pRowList[i];
+ bDataAtCol = FALSE;
+ }
+ else
+ {
+ for (SCSIZE j=0; j<=PIVOT_MAXFUNC; j++) // incl. "auto"
+ if (aRowArr[i].nFuncMask & nFuncMaskArr[j])
+ aRowArr[i].nFuncCount++;
+ }
+ }
+ bValidArea = FALSE;
+}
+
+void ScPivot::GetRowFields(PivotField* pFieldArr, SCSIZE& rCount) const
+{
+ for (SCSIZE i=0; i<nRowCount; i++)
+ pFieldArr[i] = aRowArr[i];
+ rCount = nRowCount;
+}
+
+void ScPivot::SetDataFields(const PivotField* pFieldArr, SCSIZE nCount)
+{
+ USHORT nFuncNo;
+ SCSIZE i;
+
+ //
+ // nDataCount vorausberechnen (wie unten)
+ //
+
+ nDataCount = 0;
+ for (i = 0; i < nCount; i++)
+ for (nFuncNo=0; nFuncNo<PIVOT_MAXFUNC; nFuncNo++)
+ if (pFieldArr[i].nFuncMask & nFuncMaskArr[nFuncNo])
+ if (nDataCount+1 < PIVOT_MAXFIELD)
+ ++nDataCount;
+
+ //
+ // Eintraege anpassen
+ //
+
+ if ((nRowCount == 1) && (aRowArr[0].nCol == PIVOT_DATA_FIELD) && (nDataCount == 1))
+ {
+ aColArr[nColCount] = aRowArr[0];
+ pDataList = pColList[nColCount];
+ nColCount++;
+ nRowCount--;
+ bDataAtCol = TRUE;
+ }
+ if ((nColCount == 1) && (aColArr[0].nCol == PIVOT_DATA_FIELD) && (nDataCount == 1))
+ {
+ aRowArr[nRowCount] = aColArr[0];
+ pDataList = pRowList[nRowCount];
+ nRowCount++;
+ nColCount--;
+ bDataAtCol = FALSE;
+ }
+
+ if ((nDataCount == 1)
+ && (aColArr[nColCount-1].nCol != PIVOT_DATA_FIELD)
+ && (aColArr[nRowCount-1].nCol != PIVOT_DATA_FIELD))
+ {
+ if (bDataAtCol)
+ {
+ PivotField aField;
+ SCSIZE nIndex = PIVOT_MAXFIELD;
+ for (i=0; i<nColCount; i++)
+ {
+ if (aColArr[i].nCol == PIVOT_DATA_FIELD)
+ {
+ aField = aColArr[i];
+ nIndex = i;
+ }
+ }
+ DBG_ASSERT(nIndex < PIVOT_MAXFIELD, "no data field (GPF in old versions!)");
+ if ( nIndex < PIVOT_MAXFIELD )
+ {
+ memcpy(&aColArr[nIndex], &aColArr[nIndex+1], (PIVOT_MAXFIELD - nIndex - 1) * sizeof(PivotField));
+ aColArr[nColCount-1] = aField;
+ pDataList = pColList[nColCount-1];
+ }
+ }
+ else
+ {
+ PivotField aField;
+ SCSIZE nIndex = PIVOT_MAXFIELD;
+ for (i=0; i<nRowCount; i++)
+ {
+ if (aRowArr[i].nCol == PIVOT_DATA_FIELD)
+ {
+ aField = aRowArr[i];
+ nIndex = i;
+ }
+ }
+ DBG_ASSERT(nIndex < PIVOT_MAXFIELD, "no data field (GPF in old versions!)");
+ if ( nIndex < PIVOT_MAXFIELD )
+ {
+ memcpy(&aRowArr[nIndex], &aRowArr[nIndex+1], (PIVOT_MAXFIELD - nIndex - 1) * sizeof(PivotField));
+ aRowArr[nRowCount-1] = aField;
+ pDataList = pRowList[nRowCount-1];
+ }
+ }
+ }
+
+ //
+ // Datenfelder in Eintraege mit nur einer Funktion aufteilen
+ //
+
+ pDataList->FreeAll();
+ nDataCount = 0;
+ for (i = 0; i < nCount; i++)
+ {
+ for (nFuncNo=0; nFuncNo<PIVOT_MAXFUNC; nFuncNo++)
+ if (pFieldArr[i].nFuncMask & nFuncMaskArr[nFuncNo])
+ if (nDataCount+1 < PIVOT_MAXFIELD)
+ {
+ aDataArr[nDataCount] = pFieldArr[i];
+ aDataArr[nDataCount].nFuncCount = 0;
+ aDataArr[nDataCount].nFuncMask = nFuncMaskArr[nFuncNo];
+
+ String aStr;
+ pDoc->GetString(aDataArr[nDataCount].nCol, nSrcRow1, nSrcTab, aStr);
+ if (aStr.Len() == 0)
+ aStr = ScColToAlpha( aDataArr[nDataCount].nCol );
+ TypedStrData* pStrData = new TypedStrData(aStr);
+ if (!(pDataList->AtInsert(pDataList->GetCount(), pStrData)))
+ {
+ delete pStrData;
+ DBG_ERROR("Fehler bei pDataList->AtInsert");
+ }
+
+ ++nDataCount;
+ }
+ }
+
+ //
+ //
+ //
+
+ bValidArea = FALSE;
+}
+
+void ScPivot::GetDataFields(PivotField* pFieldArr, SCSIZE& rCount) const
+{
+/* for (SCSIZE i=0; i<nDataCount; i++)
+ pFieldArr[i] = aDataArr[i];
+ rCount = nDataCount;
+*/
+
+ rCount = 0;
+ for (SCSIZE i=0; i<nDataCount; i++)
+ {
+ BOOL bFound = FALSE;
+ for (SCSIZE j=0; j<rCount && !bFound; j++)
+ if (pFieldArr[j].nCol == aDataArr[i].nCol)
+ {
+ // add to previous column only if new bits aren't already set there
+ if ( ( pFieldArr[j].nFuncMask & aDataArr[i].nFuncMask ) == 0 )
+ {
+ pFieldArr[j].nFuncMask |= aDataArr[i].nFuncMask;
+ pFieldArr[j].nFuncCount++;
+ bFound = TRUE;
+ }
+ }
+ if (!bFound)
+ {
+ pFieldArr[rCount] = aDataArr[i];
+ ++rCount;
+ }
+ }
+}
+
+BOOL ScPivot::CreateData(BOOL bKeepDest)
+{
+ //
+ //
+ //
+
+ SCCOL nOldCol2 = nDestCol2;
+ SCROW nOldRow2 = nDestRow2;
+
+ pColRef = new PivotColRef[MAXCOL];
+ aQuery.nCol1 = nSrcCol1;
+ aQuery.nRow1 = nSrcRow1;
+ aQuery.nCol2 = nSrcCol2;
+ aQuery.nRow2 = nSrcRow2;
+ aQuery.bHasHeader = bHasHeader;
+ BOOL bRet = CreateFields();
+ if (bRet)
+ {
+ SCSIZE i=0; // nDataMult berechnen - nach CreateFields, vor CreateFieldData !!!
+ nDataMult = 1;
+ if (nDataCount > 1)
+ {
+ if (bDataAtCol)
+ {
+ while (i<nColCount && aColArr[i].nCol != PIVOT_DATA_FIELD) i++;
+ i++;
+ while (i<nColCount)
+ nDataMult *= pColList[i++]->GetCount();
+ }
+ else
+ {
+ while (i<nRowCount && aRowArr[i].nCol != PIVOT_DATA_FIELD) i++;
+ i++;
+ while (i<nRowCount)
+ nDataMult *= pRowList[i++]->GetCount();
+ }
+ }
+ DBG_ASSERT(nDataMult,"nDataMult==0");
+
+ CalcArea();
+ if ((ValidCol(nDestCol2)) && (ValidRow(nDestRow2)))
+ {
+ CreateFieldData();
+ bValidArea = TRUE;
+ }
+ else
+ bRet = FALSE;
+ }
+
+ if ( bKeepDest )
+ {
+ bValidArea = TRUE; //! ???
+ nDestCol2 = nOldCol2;
+ nDestRow2 = nOldRow2;
+ }
+
+ return bRet;
+}
+
+void ScPivot::DrawData()
+{
+ ScProgress aProgress( pDoc->GetDocumentShell(), ScGlobal::GetRscString(STR_PIVOT_PROGRESS), nDestRow2-nDestRow1 );
+
+ SCSIZE i;
+
+ SCCOL nCol;
+ SCROW nRow;
+ String aStr;
+ pDoc->pTab[nDestTab]->DeleteArea(nDestCol1, nDestRow1, nDestCol2, nDestRow2, IDF_ALL);
+
+ if ( nDataStartRow > nDestRow1+nFirstLine )
+ SetStyle(nDestCol1, nDestRow1+nFirstLine, nDestCol2, nDataStartRow-1, PIVOT_STYLE_TOP);
+ SetStyle(nDataStartCol, nDataStartRow, nDestCol2, nDestRow2, PIVOT_STYLE_INNER);
+
+ pDoc->SetString(nDestCol1, nDestRow1, nDestTab, ScGlobal::GetRscString(STR_CELL_FILTER));
+ // Kategorie 1
+ SetButton(nDestCol1, nDestRow1, nDestCol1, nDestRow1);
+
+ if (bHasHeader) // Spalten / Zeilennamen ausgeben
+ {
+ if (nColCount != 0)
+ {
+ nCol = nDestCol1;
+ nRow = nDataStartRow - 1;
+ for (i=0; i<nColCount; i++)
+ {
+ if (aColArr[i].nCol != PIVOT_DATA_FIELD)
+ {
+ pDoc->GetString(aColArr[i].nCol, nSrcRow1, nSrcTab, aStr);
+ if ( !aStr.Len() )
+ aStr = ScColToAlpha( aColArr[i].nCol );
+ pDoc->SetString(nCol, nRow, nDestTab, aStr);
+ // Kategorie 2
+ nCol++;
+ }
+ else if (nDataCount > 1)
+ {
+ pDoc->SetString(nCol, nRow, nDestTab, *pLabelData);
+ // Kategorie 3
+ nCol++;
+ }
+ }
+ SetButton(nDestCol1, nRow, nCol-1, nRow);
+ SetStyle(nDestCol1, nRow, nCol-1, nRow, PIVOT_STYLE_FIELDNAME);
+ }
+ if (nRowCount != 0)
+ {
+ nCol = nDataStartCol;
+ nRow = nDestRow1 + nFirstLine;
+ for (i=0; i<nRowCount; i++)
+ {
+ if (aRowArr[i].nCol != PIVOT_DATA_FIELD)
+ {
+ pDoc->GetString(aRowArr[i].nCol, nSrcRow1, nSrcTab, aStr);
+ if ( !aStr.Len() )
+ aStr = ScColToAlpha( aRowArr[i].nCol );
+ pDoc->SetString(nCol, nRow, nDestTab, aStr);
+ // Kategorie 4
+ nCol++;
+ }
+ else if (nDataCount > 1)
+ {
+ pDoc->SetString(nCol, nRow, nDestTab, *pLabelData);
+ // Kategorie 5
+ nCol++;
+ }
+ }
+ SetButton(nDataStartCol, nRow, nCol-1, nRow);
+ SetStyle(nDataStartCol, nRow, nCol-1, nRow, PIVOT_STYLE_FIELDNAME);
+ }
+ }
+
+ BOOL bNoRows = (nRowCount == 0) || ( nRowCount == 1 && aRowArr[0].nCol == PIVOT_DATA_FIELD );
+ BOOL bNoCols = (nColCount == 0) || ( nColCount == 1 && aColArr[0].nCol == PIVOT_DATA_FIELD );
+ if (!bMakeTotalCol) bNoRows = TRUE;
+ if (!bMakeTotalRow) bNoCols = TRUE;
+
+ SCCOL nTotalCol = nDestCol2;
+ SCROW nTotalRow = nDestRow2;
+ if (bDataAtCol)
+ nTotalRow = sal::static_int_cast<SCROW>( nTotalRow - ( nDataCount - 1 ) );
+ else
+ nTotalCol = sal::static_int_cast<SCCOL>( nTotalCol - ( nDataCount - 1 ) );
+
+ // Spaltenkoepfe ausgeben und ColRef initialisieren
+ // (String-Collections sind initialisiert)
+ nDataIndex = 0;
+ nColIndex = 0;
+ nCol = nDataStartCol;
+ nRecCount = 0;
+ RowToTable(0, nCol);
+
+ // Zeilenkoepfe und Daten ausgeben
+ // (ruft SetDataLine/SetFuncLine auf)
+ nRowIndex = 0;
+ nRow = nDataStartRow;
+ ColToTable(0, nRow, aProgress);
+
+ // Gesamtergebnis-Zeilen
+
+ if (!bNoCols)
+ {
+ if (bDataAtCol)
+ for (SCSIZE nTotCnt = 0; nTotCnt<nDataCount; nTotCnt++)
+ SetFuncLine(nDataStartCol, nRow+nTotCnt, nDestTab,
+ aDataArr[nTotCnt].nFuncMask, nTotCnt, 0, nDataRowCount);
+ else
+ SetFuncLine(nDataStartCol, nRow, nDestTab, PIVOT_FUNC_AUTO, SCSIZE_MAX, 0, nDataRowCount);
+ }
+
+
+ // Rahmen Spaltenergebnis
+
+ if (!bNoRows)
+ {
+ if (!bDataAtCol)
+ {
+ for (i=0; i<nDataCount; i++)
+ {
+ String aLab = *pLabelTotal;
+ aLab += ' ';
+ aLab += *pLabel[lcl_MaskToIndex( aDataArr[i].nFuncMask )];
+ aLab += ' ';
+ aLab += pDataList->GetString(sal::static_int_cast<USHORT>(i));
+ pDoc->SetString(sal::static_int_cast<SCCOL>(nTotalCol+i),
+ sal::static_int_cast<SCROW>(nDestRow1 + nFirstLine), nDestTab, aLab);
+ // Kategorie 6
+ }
+ }
+ else
+ {
+ pDoc->SetString(nTotalCol, nDestRow1 + nFirstLine, nDestTab, *pLabelTotal);
+ // Kategorie 7
+ }
+
+ if ( nDataStartRow > 0 )
+ SetStyle(nTotalCol, nDestRow1+nFirstLine, nDestCol2, nDataStartRow-1, PIVOT_STYLE_TITLE);
+ SetStyle(nTotalCol, nDataStartRow, nDestCol2, nDestRow2, PIVOT_STYLE_RESULT);
+ SetFrame(nTotalCol, nDestRow1 + nFirstLine, nDestCol2, nDestRow2);
+ }
+
+ // Rahmen Zeilenergebnis
+
+ if (!bNoCols)
+ {
+ if (bDataAtCol)
+ {
+ for (i=0; i<nDataCount; i++)
+ {
+ String aLab = *pLabelTotal;
+ aLab += ' ';
+ aLab += *pLabel[lcl_MaskToIndex( aDataArr[i].nFuncMask )];
+ aLab += ' ';
+ aLab += pDataList->GetString(sal::static_int_cast<USHORT>(i));
+ pDoc->SetString(nDestCol1, nTotalRow+i, nDestTab, aLab);
+ // Kategorie 8
+ }
+ }
+ else
+ {
+ pDoc->SetString(nDestCol1, nTotalRow, nDestTab, *pLabelTotal);
+ // Kategorie 9
+ }
+
+ if ( nDataStartCol > 0 )
+ SetStyle(nDestCol1, nTotalRow, nDataStartCol-1, nDestRow2, PIVOT_STYLE_TITLE);
+ SetStyle(nDataStartCol, nTotalRow, nDestCol2, nDestRow2, PIVOT_STYLE_RESULT);
+ SetFrame(nDestCol1, nTotalRow, nDestCol2, nDestRow2);
+ }
+
+ // Rahmen gesamt
+ SetFrame(nDestCol1, nDestRow1 + nFirstLine, nDestCol2, nDestRow2, 40);
+}
+
+void ScPivot::ReleaseData()
+{
+ for (SCSIZE i = 0; i < PIVOT_MAXFIELD; i++)
+ {
+ pColList[i]->FreeAll();
+ pRowList[i]->FreeAll();
+ }
+ if (ppDataArr)
+ {
+ for (SCSIZE i=0; i<nDataRowCount; i++)
+ delete[] ppDataArr[i];
+ delete[] ppDataArr;
+ ppDataArr = NULL;
+ }
+ nDataColCount = 0;
+ nDataRowCount = 0;
+ delete[] pColRef;
+ pColRef = NULL;
+}
+
+BOOL ScPivot::IsPivotAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
+{
+ if (bValidArea)
+ return ( nTab == nDestTab
+ && nCol >= nDestCol1 && nCol <= nDestCol2
+ && nRow >= nDestRow1 && nRow <= nDestRow2 );
+ else
+ return FALSE;
+}
+
+BOOL ScPivot::IsFilterAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
+{
+ if (bValidArea)
+ return (nCol == nDestCol1 && nRow == nDestRow1 && nTab == nDestTab);
+ else
+ return FALSE;
+}
+
+BOOL ScPivot::GetColFieldAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, SCCOL& rField) const
+{
+ rField = 0;
+ BOOL bRet = FALSE;
+ if (bValidArea)
+ {
+ bRet = ( nCol >= nDestCol1 && nCol < nDataStartCol
+ && nRow == nDataStartRow - 1
+ && nTab == nDestTab );
+ if (bRet)
+ {
+ rField = aColArr[nCol - nDestCol1].nCol;
+ if (rField == PIVOT_DATA_FIELD)
+ bRet = (nDataCount > 1);
+ }
+ }
+ return bRet;
+}
+
+BOOL ScPivot::GetRowFieldAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab, SCCOL& rField) const
+{
+ rField = 0;
+ BOOL bRet = FALSE;
+ if (bValidArea)
+ {
+ bRet = ( nCol >= nDataStartCol && nCol < sal::static_int_cast<SCCOL>(nDataStartCol + nRowCount)
+ && nRow == nDestRow1 + nFirstLine
+ && nTab == nDestTab );
+ if (bRet)
+ {
+ rField = aRowArr[nCol - nDataStartCol].nCol;
+ if (rField == PIVOT_DATA_FIELD)
+ bRet = (nDataCount > 1);
+ }
+ }
+ return bRet;
+}
+
+
+//--------------------------------------------------------------------------------------------------
+// Private Methoden
+//--------------------------------------------------------------------------------------------------
+
+BOOL ScPivot::CreateFields()
+{
+ SCSIZE i;
+ SCROW nRow;
+ SCROW nHeader;
+ String aStr;
+ TypedStrData* pStrData;
+ if (bHasHeader)
+ nHeader = 1;
+ else
+ nHeader = 0;
+
+ // Sortieren nach Benutzerdefinierte Listen ??
+ for (i = 0; i < nColCount; i++)
+ {
+ if (aColArr[i].nCol != PIVOT_DATA_FIELD)
+ {
+ pDoc->GetString(aColArr[i].nCol, nSrcRow1 + nHeader, nSrcTab, aStr);
+ pColList[i]->SetUserData(ScGlobal::GetUserList()->GetData(aStr));
+ }
+ else
+ pColList[i]->SetUserData(NULL);
+ }
+ for (i = 0; i < nRowCount; i++)
+ {
+ if (aRowArr[i].nCol != PIVOT_DATA_FIELD)
+ {
+ pDoc->GetString(aRowArr[i].nCol, nSrcRow1 + nHeader, nSrcTab, aStr);
+ pRowList[i]->SetUserData(ScGlobal::GetUserList()->GetData(aStr));
+ }
+ else
+ pRowList[i]->SetUserData(NULL);
+ }
+
+ ScAddress aSrcAdr( nSrcCol1, 0, nSrcTab );
+ for (nRow = nSrcRow1 + nHeader; nRow <= nSrcRow2; nRow++)
+ {
+ BOOL bValidLine = TRUE;
+ if (bIgnoreEmpty)
+ {
+ aSrcAdr.SetRow( nRow );
+ bValidLine = !lcl_IsEmptyLine( pDoc, aSrcAdr, nSrcCol2 );
+ }
+ if (bValidLine)
+ bValidLine = pDoc->pTab[nSrcTab]->ValidQuery(nRow, aQuery);
+ if (bValidLine)
+ {
+ // Sortierte Liste der Felder erzeugen
+ //! statt GetCategoryString leere weglassen !
+
+ for (i = 0; i < nColCount; i++)
+ {
+ if (aColArr[i].nCol != PIVOT_DATA_FIELD)
+ {
+ SCROW nCatRow = bDetectCat ? GetCategoryRow( aColArr[i].nCol, nRow ) : nRow;
+ pStrData = new TypedStrData( pDoc, aColArr[i].nCol, nCatRow, nSrcTab, TRUE );
+ if (!(pColList[i]->Insert(pStrData)))
+ delete pStrData;
+ }
+ }
+ for (i = 0; i < nRowCount; i++)
+ {
+ if (aRowArr[i].nCol != PIVOT_DATA_FIELD)
+ {
+ SCROW nCatRow = bDetectCat ? GetCategoryRow( aRowArr[i].nCol, nRow ) : nRow;
+ pStrData = new TypedStrData( pDoc, aRowArr[i].nCol, nCatRow, nSrcTab, TRUE );
+ if (!(pRowList[i]->Insert(pStrData)))
+ delete pStrData;
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+void ScPivot::CreateFieldData()
+{
+ SCSIZE* pRowListIndex = nRowCount ? new SCSIZE[nRowCount] : NULL;
+ SCSIZE* pColListIndex = nColCount ? new SCSIZE[nColCount] : NULL;
+
+ SCSIZE i,j,k;
+
+ ppDataArr = new SubTotal*[nDataRowCount];
+ for (i=0; i<nDataRowCount; i++)
+ ppDataArr[i] = new SubTotal[nDataColCount];
+
+ if (bDataAtCol)
+ for (j=0; j<nDataRowCount; j++)
+ for (i=0; i<nDataColCount; i++)
+ ppDataArr[j][i].nIndex = j/nDataMult%nDataCount;
+ else
+ for (j=0; j<nDataRowCount; j++)
+ for (i=0; i<nDataColCount; i++)
+ ppDataArr[j][i].nIndex = i/nDataMult%nDataCount;
+
+ SCROW nHeader;
+ if (bHasHeader)
+ nHeader = 1;
+ else
+ nHeader = 0;
+ ScAddress aSrcAdr( nSrcCol1, 0, nSrcTab );
+ for (SCROW nRow = nSrcRow1 + nHeader; nRow <= nSrcRow2; nRow++)
+ {
+ BOOL bValidLine = TRUE;
+ if (bIgnoreEmpty)
+ {
+ aSrcAdr.SetRow( nRow );
+ bValidLine = !lcl_IsEmptyLine( pDoc, aSrcAdr, nSrcCol2 );
+ }
+ if (bValidLine)
+ bValidLine = pDoc->pTab[nSrcTab]->ValidQuery(nRow, aQuery);
+ if (bValidLine)
+ {
+ // Indizes der Kategorien nur einmal ausserhalb nDataCount
+ for (j=0; j<nRowCount; j++)
+ if (aRowArr[j].nCol != PIVOT_DATA_FIELD)
+ {
+ SCROW nCatRow = bDetectCat ? GetCategoryRow( aRowArr[j].nCol, nRow ) : nRow;
+ TypedStrData aStrData( pDoc, aRowArr[j].nCol, nCatRow, nSrcTab, TRUE );
+ pRowListIndex[j] = pRowList[j]->GetIndex(&aStrData);
+ }
+ for (j=0; j<nColCount; j++)
+ if (aColArr[j].nCol != PIVOT_DATA_FIELD)
+ {
+ SCROW nCatRow = bDetectCat ? GetCategoryRow( aColArr[j].nCol, nRow ) : nRow;
+ TypedStrData aStrData( pDoc, aColArr[j].nCol, nCatRow, nSrcTab, TRUE );
+ pColListIndex[j] = pColList[j]->GetIndex(&aStrData);
+ }
+
+ String aStr;
+ SCSIZE nCIndex;
+ SCSIZE nRIndex;
+ SCSIZE nIndex;
+ ScAddress aAdr( 0, nRow, nSrcTab );
+
+ for (i=0; i<nDataCount; i++)
+ {
+ // ColIndex Berechnen
+ nCIndex = 0;
+ for (j=0; j<nRowCount; j++)
+ {
+ if (aRowArr[j].nCol == PIVOT_DATA_FIELD)
+ nIndex = i;
+ else
+ nIndex = pRowListIndex[j];
+ if (nIndex)
+ {
+ for (k=j+1; k<nRowCount; k++)
+ nIndex *= pRowList[k]->GetCount();
+ nCIndex += nIndex;
+ }
+ }
+ // RowIndex Berechnen
+ nRIndex = 0;
+ for (j=0; j<nColCount; j++)
+ {
+ if (aColArr[j].nCol == PIVOT_DATA_FIELD)
+ nIndex = i;
+ else
+ nIndex = pColListIndex[j];
+ if (nIndex)
+ {
+ for (k=j+1; k<nColCount; k++)
+ nIndex *= pColList[k]->GetCount();
+ nRIndex += nIndex;
+ }
+ }
+ // Daten eintragen
+ if ((nCIndex < nDataColCount) && (nRIndex < nDataRowCount))
+ {
+ DBG_ASSERT(ppDataArr[nRIndex][nCIndex].nIndex == i, "falsch init.");
+
+ ppDataArr[nRIndex][nCIndex].nIndex = i;
+ aAdr.SetCol( aDataArr[i].nCol );
+ CellType eCellType = pDoc->GetCellType( aAdr );
+ if ((eCellType != CELLTYPE_NONE) && (eCellType != CELLTYPE_NOTE))
+ {
+ BOOL bValue = (eCellType == CELLTYPE_VALUE);
+ if (eCellType == CELLTYPE_FORMULA)
+ {
+ ScBaseCell* pCell = pDoc->GetCell( aAdr );
+ bValue = ((ScFormulaCell*)pCell)->IsValue();
+ }
+
+ if (bValue)
+ {
+ double nVal = pDoc->GetValue( aAdr );
+ ppDataArr[nRIndex][nCIndex].Update(nVal);
+ }
+ else
+ ppDataArr[nRIndex][nCIndex].UpdateNoVal(); // nur nCount
+ }
+ }
+ }
+ }
+ }
+
+ delete pColListIndex;
+ delete pRowListIndex;
+}
+
+void ScPivot::CalcArea()
+{
+ BOOL bNoRows = (nRowCount == 0) || ( nRowCount == 1 && aRowArr[0].nCol == PIVOT_DATA_FIELD );
+ BOOL bNoCols = (nColCount == 0) || ( nColCount == 1 && aColArr[0].nCol == PIVOT_DATA_FIELD );
+ if (!bMakeTotalCol) bNoRows = TRUE;
+ if (!bMakeTotalRow) bNoCols = TRUE;
+
+ // StartSpalte/StartZeile des Datenbereichs berechnen
+ if (bDataAtCol)
+ {
+ if (nDataCount > 1)
+ nDataStartCol = sal::static_int_cast<SCCOL>(nDestCol1 + nColCount);
+ else
+ nDataStartCol = sal::static_int_cast<SCCOL>(nDestCol1 + Max(static_cast<SCSIZE>(0), nColCount - 1));
+ }
+ else
+ nDataStartCol = sal::static_int_cast<SCCOL>(nDestCol1 + nColCount);
+ if (!bDataAtCol)
+ {
+ if (nDataCount > 1)
+ nDataStartRow = nDestRow1 + nRowCount + nFirstLine + 1;
+ else
+ nDataStartRow = nDestRow1 + Max(static_cast<SCSIZE>(0), nRowCount - 1) + nFirstLine + 1;
+ }
+ else
+ nDataStartRow = nDestRow1 + nRowCount + nFirstLine + 1;
+
+ //
+ // Groesse der PivotTabelle berechnen
+ //
+
+ if (nRowCount == 0 || (nRowCount==1 && aRowArr[0].nCol==PIVOT_DATA_FIELD && nDataCount==1))
+ {
+ nDataColCount = 1;
+ if (nDataCount == 1)
+ nDestCol2 = sal::static_int_cast<SCCOL>(nDestCol1 + nColCount - 1);
+ else
+ nDestCol2 = sal::static_int_cast<SCCOL>(nDestCol1 + nColCount);
+ }
+ else
+ {
+ SCSIZE nDx;
+ // Anzahl Spalten
+ if ((aRowArr[nRowCount-1].nCol == PIVOT_DATA_FIELD) && (nDataCount == 1))
+ nDx = 2;
+ else
+ nDx = 1;
+ SCSIZE nColLines = pRowList[nRowCount-nDx]->GetCount(); // SCSIZE to recognize overflow
+ nDataColCount = pRowList[nRowCount-nDx]->GetCount();
+ for (SCSIZE i=nRowCount-nDx; i-- > 0; )
+ {
+ nColLines *= pRowList[i]->GetCount();
+ nDataColCount *= pRowList[i]->GetCount();
+ if (!bDataAtCol)
+ nColLines += (pRowList[i]->GetCount() * aRowArr[i].nFuncCount * nDataCount);
+ else
+ nColLines += (pRowList[i]->GetCount() * aRowArr[i].nFuncCount);
+ }
+ /*
+ // Ergebnisspalten des letzten Elements
+ if (aRowArr[nRowCount-1].nCol != PIVOT_DATA_FIELD)
+ nColLines += (pRowList[nRowCount-1]->GetCount() * aRowArr[nRowCount-1].nFuncCount);
+ */
+ if (nColLines > static_cast<SCSIZE>(MAXCOL))
+ nDestCol2 = MAXCOL+2; // ungueltig, 1 wird unten abgezogen
+ else if (bDataAtCol)
+ {
+ if (nDataCount > 1)
+ nDestCol2 = sal::static_int_cast<SCCOL>(nDestCol1 + nColCount + nColLines);
+ else
+ nDestCol2 = sal::static_int_cast<SCCOL>(nDestCol1 + (nColCount - 1) + nColLines);
+ if (!bMakeTotalCol)
+ --nDestCol2;
+ }
+ else
+ nDestCol2 = sal::static_int_cast<SCCOL>(nDestCol1 + nColCount + nColLines);
+ }
+
+ if (nColCount == 0 || (nColCount==1 && aColArr[0].nCol==PIVOT_DATA_FIELD && nDataCount==1))
+ {
+ nDataRowCount = 1;
+ if (nDataCount == 1)
+ nDestRow2 = nDestRow1 + (nRowCount - 1) + nFirstLine + 1;
+ else
+ nDestRow2 = nDestRow1 + nRowCount + nFirstLine + 1;
+ }
+ else
+ {
+ SCSIZE nDx;
+ // Anzahl Zeilen
+ if ((aColArr[nColCount-1].nCol == PIVOT_DATA_FIELD) && (nDataCount == 1))
+ nDx = 2;
+ else
+ nDx = 1;
+ SCSIZE nRowLines = pColList[nColCount-nDx]->GetCount(); // SCSIZE to recognize overflow
+ nDataRowCount = pColList[nColCount-nDx]->GetCount();
+ for (SCSIZE i=nColCount-nDx; i-- > 0; )
+ {
+ nRowLines *= pColList[i]->GetCount();
+ nDataRowCount *= pColList[i]->GetCount();
+ if (bDataAtCol)
+ nRowLines += (pColList[i]->GetCount() * aColArr[i].nFuncCount * nDataCount);
+ else
+ nRowLines += (pColList[i]->GetCount() * aColArr[i].nFuncCount);
+ }
+ /*
+ // Ergebniszeilen des letzten Elements
+ if (aColArr[nColCount-1].nCol != PIVOT_DATA_FIELD)
+ nRowLines += (pColList[nColCount-1]->GetCount() * aColArr[nColCount-1].nFuncCount);
+ */
+ if (nRowLines > static_cast<SCSIZE>(MAXROW))
+ nDestRow2 = MAXROW+2; // ungueltig, 1 wird unten abgezogen
+ else if (!bDataAtCol)
+ {
+ if (nDataCount > 1)
+ nDestRow2 = nDestRow1 + nRowCount + nRowLines + nFirstLine + 1;
+ else
+ nDestRow2 = nDestRow1 + (nRowCount - 1) + nRowLines + nFirstLine + 1;
+ if (!bMakeTotalRow)
+ --nDestRow2;
+ }
+ else
+ nDestRow2 = nDestRow1 + nRowCount + nRowLines + nFirstLine + 1;
+ }
+
+ if (bDataAtCol)
+ {
+ if (!bNoCols)
+ nDestRow2 += nDataCount;
+ nDestRow2 --;
+ }
+ else
+ {
+ if (!bNoRows)
+ nDestCol2 = sal::static_int_cast<SCCOL>(nDestCol2 + nDataCount);
+ nDestCol2 --;
+ }
+}
+
+void ScPivot::SetDataLine(SCCOL nCol, SCROW nRow, SCTAB /* nTab */, SCSIZE nRIndex)
+{
+ SCSIZE nCIndex2;
+
+ SubTotal aGrandTotal[PIVOT_MAXFIELD]; // pro Daten-Feld
+
+ for (SCSIZE i=0; i < nColIndex; i++)
+ {
+ SCSIZE nCIndex = pColRef[i].nDataIndex;
+ if (nCIndex != sal::static_int_cast<SCSIZE>(PIVOT_FUNC_REF))
+ {
+// if ( ppDataArr[nRIndex][nCIndex].GetCount() )
+ {
+ SCSIZE nDIndex = ppDataArr[nRIndex][nCIndex].nIndex;
+ SetValue( sal::static_int_cast<SCCOL>(nCol+i), nRow, ppDataArr[nRIndex][nCIndex], aDataArr[nDIndex].nFuncMask );
+ // Kategorie 18
+
+ if (bDataAtCol)
+ aGrandTotal[0].Update(ppDataArr[nRIndex][nCIndex]);
+ else
+ aGrandTotal[nDIndex].Update(ppDataArr[nRIndex][nCIndex]);
+ }
+ }
+ else
+ {
+ SubTotal aTotal;
+ SCSIZE k = i-1;
+ while ((pColRef[k].nDataIndex == sal::static_int_cast<SCSIZE>(PIVOT_FUNC_REF)) && (k > 0))
+ k--;
+ for (SCSIZE j=k+1; (j-- > 0) && (pColRef[j].nRecCount > pColRef[i].nRecCount); )
+ {
+ nCIndex2 = pColRef[j].nDataIndex;
+ if (nCIndex2 != sal::static_int_cast<SCSIZE>(PIVOT_FUNC_REF))
+ {
+ if ((pColRef[i].nIndex == ppDataArr[nRIndex][nCIndex2].nIndex) ||
+ (pColRef[i].nIndex == SCSIZE_MAX))
+ {
+ aTotal.Update( ppDataArr[nRIndex][nCIndex2] );
+ }
+ }
+ }
+
+ USHORT nFunc = pColRef[i].nFuncMask;
+ if (nFunc == PIVOT_FUNC_AUTO)
+ nFunc = aDataArr[nRIndex/nDataMult%nDataCount].nFuncMask;
+ SetValue( sal::static_int_cast<SCCOL>(nCol+i), nRow, aTotal, nFunc );
+ // Kategorie 19
+ }
+ }
+
+ BOOL bNoRows = (nRowCount == 0) || ( nRowCount == 1 && aRowArr[0].nCol == PIVOT_DATA_FIELD );
+ if (!bMakeTotalCol) bNoRows = TRUE;
+
+ if (!bNoRows)
+ {
+ if (bDataAtCol)
+ {
+ SetValue( nDestCol2, nRow, aGrandTotal[0], aDataArr[nRIndex/nDataMult%nDataCount].nFuncMask );
+ // Kategorie 20
+ }
+ else
+ {
+ SCCOL nTotalCol = sal::static_int_cast<SCCOL>(nDestCol2 - nDataCount + 1);
+ for (SCSIZE nTotCnt = 0; nTotCnt<nDataCount; nTotCnt++)
+ {
+ SetValue( sal::static_int_cast<SCCOL>(nTotalCol+nTotCnt), nRow, aGrandTotal[nTotCnt], aDataArr[nTotCnt].nFuncMask );
+ // Kategorie 21
+ }
+ }
+ }
+}
+
+void ScPivot::SetFuncLine(SCCOL nCol, SCROW nRow, SCTAB /* nTab */, USHORT nFunc, SCSIZE nIndex, SCSIZE nStartRIndex, SCSIZE nEndRIndex)
+{
+ SCSIZE nSubtCount = 0;
+ SubTotal aGrandTotal[PIVOT_MAXFIELD];
+ USHORT nThisFunc = nFunc;
+
+ for (SCSIZE i=0; i<nColIndex; i++)
+ {
+ SCSIZE nCIndex = pColRef[i].nDataIndex;
+ if (nCIndex != sal::static_int_cast<SCSIZE>(PIVOT_FUNC_REF))
+ {
+ SubTotal aTotal;
+ for (SCSIZE j = nStartRIndex; j < nEndRIndex; j++)
+ {
+ SCSIZE nDIndex = ppDataArr[j][nCIndex].nIndex;
+ if ((nIndex == nDIndex) || (nIndex == SCSIZE_MAX))
+ {
+ aTotal.Update( ppDataArr[j][nCIndex] );
+ }
+ }
+
+ if (bDataAtCol)
+ aGrandTotal[0].Update( aTotal );
+ else
+ aGrandTotal[nCIndex/nDataMult%nDataCount].Update( aTotal ); //! immer ?
+
+ if (nFunc == PIVOT_FUNC_AUTO)
+ {
+ if (bDataAtCol)
+ {
+ if (nIndex<nDataCount)
+ nThisFunc = aDataArr[nIndex].nFuncMask;
+ else
+ {
+ DBG_ERROR("wat fuer'n Index ???");
+ }
+ }
+ else
+ nThisFunc = aDataArr[nCIndex/nDataMult%nDataCount].nFuncMask;
+ }
+ SetValue( sal::static_int_cast<SCCOL>(nCol+i), nRow, aTotal, nThisFunc );
+ // Kategorie 22
+ }
+ else
+ { // Kreuzungspunkte kompatibel ?
+
+ if ( nFunc == pColRef[i].nFuncMask )
+ {
+ SCSIZE nEffIndex = nIndex;
+ if (nEffIndex == SCSIZE_MAX)
+ {
+ nEffIndex = nSubtCount % nDataCount;
+ ++nSubtCount;
+ }
+ SubTotal aTotal;
+
+ SCSIZE k = i-1;
+ while ((pColRef[k].nDataIndex == sal::static_int_cast<SCSIZE>(PIVOT_FUNC_REF)) && (k > 0))
+ k--;
+ for (SCSIZE j=k+1; (j-- > 0) && (pColRef[j].nRecCount > pColRef[i].nRecCount); )
+ {
+ nCIndex = pColRef[j].nDataIndex;
+ if (nCIndex != sal::static_int_cast<SCSIZE>(PIVOT_FUNC_REF))
+ {
+ for (SCSIZE nRIndex = nStartRIndex; nRIndex < nEndRIndex; nRIndex++)
+ {
+ SCSIZE nDIndex = ppDataArr[nRIndex][nCIndex].nIndex;
+ if (nEffIndex == nDIndex)
+ {
+ aTotal.Update( ppDataArr[nRIndex][nCIndex] );
+ }
+ }
+ }
+ }
+
+ if (nFunc == PIVOT_FUNC_AUTO)
+ {
+ if (nEffIndex<nDataCount)
+ nThisFunc = aDataArr[nEffIndex].nFuncMask;
+ else
+ {
+ DBG_ERROR("wat fuer'n Index ???");
+ }
+ }
+ SetValue( sal::static_int_cast<SCCOL>(nCol+i), nRow, aTotal, nThisFunc );
+ // Kategorie 23
+ }
+ }
+ }
+
+ BOOL bNoRows = (nRowCount == 0) || ( nRowCount == 1 && aRowArr[0].nCol == PIVOT_DATA_FIELD );
+ if (!bMakeTotalCol) bNoRows = TRUE;
+
+ if (!bNoRows)
+ {
+ if (bDataAtCol)
+ {
+ if (nFunc == PIVOT_FUNC_AUTO)
+ {
+ if (nIndex<nDataCount)
+ nThisFunc = aDataArr[nIndex].nFuncMask;
+ else
+ {
+ DBG_ERROR("wat fuer'n Index ???");
+ }
+ }
+ SetValue( nDestCol2, nRow, aGrandTotal[0], nThisFunc );
+ // Kategorie 24
+ }
+ else
+ {
+ SCCOL nTotalCol = sal::static_int_cast<SCCOL>(nDestCol2 - nDataCount + 1);
+ for (SCSIZE nTotCnt = 0; nTotCnt<nDataCount; nTotCnt++)
+ {
+ if (nFunc == PIVOT_FUNC_AUTO)
+ nThisFunc = aDataArr[nTotCnt%nDataCount].nFuncMask;
+ SetValue( sal::static_int_cast<SCCOL>(nTotalCol+nTotCnt), nRow, aGrandTotal[nTotCnt], nThisFunc );
+ // Kategorie 25
+ }
+ }
+ }
+}
+
+void ScPivot::ColToTable(SCSIZE nField, SCROW& nRow, ScProgress& rProgress)
+{
+ SCCOL nCol = sal::static_int_cast<SCCOL>(nDestCol1 + nField);
+ if (nColCount == 0)
+ {
+// SetDataLine(nCol + 1, nRow, nDestTab, nRowIndex);
+ SetDataLine(nCol, nRow, nDestTab, nRowIndex);
+ nRowIndex++;
+ return;
+ }
+
+ SCSIZE nDx;
+ if ((aColArr[nColCount -1].nCol == PIVOT_DATA_FIELD) && (nDataCount == 1))
+ nDx = 2;
+ else
+ nDx = 1;
+ if (nField < nColCount - nDx)
+ {
+ for (USHORT i = 0; i < pColList[nField]->GetCount(); i++)
+ {
+ SCSIZE nSaveIndex = nRowIndex;
+ String aStr = pColList[nField]->GetString(i);
+ if (!aStr.Len()) aStr = ScGlobal::GetRscString(STR_EMPTYDATA);
+ pDoc->SetString(nCol, nRow, nDestTab, aStr);
+ // Kategorie 10
+ SCROW nSaveRow = nRow;
+ ColToTable(nField + 1, nRow, rProgress);
+ SetStyle(nCol, nSaveRow, nCol, nRow - 1, PIVOT_STYLE_CATEGORY);
+ SetFrame(nCol, nSaveRow, nCol, nRow - 1);
+ if (aColArr[nField].nFuncCount > 0) // Zwischenergebnisse eingestellt?
+ {
+ nSaveRow = nRow;
+ for (SCSIZE j=0; j<=PIVOT_MAXFUNC; j++) // incl. "auto"
+ {
+ if (aColArr[nField].nFuncMask & nFuncMaskArr[j])
+ {
+ String aLab;
+ if (bDataAtCol)
+ {
+ for (SCSIZE k=0; k < nDataCount; k++)
+ {
+ String aDataStr = pDataList->GetString(sal::static_int_cast<USHORT>(k)); // always String
+ aLab = aStr;
+ SCSIZE nFuncType;
+ if ( j==PIVOT_MAXFUNC )
+ nFuncType = lcl_MaskToIndex( aDataArr[k].nFuncMask );
+ else
+ nFuncType = j;
+ aLab += ' ';
+ aLab += *pLabel[nFuncType];
+ aLab += ' ';
+ aLab += aDataStr;
+ pDoc->SetString(nCol, nRow, nDestTab, aLab);
+ // Kategorie 11
+ SetFuncLine(nDataStartCol, nRow, nDestTab, nFuncMaskArr[j], k, nSaveIndex, nRowIndex);
+ nRow++;
+ }
+ }
+ else
+ {
+ aLab = aStr;
+ aLab += ' ';
+ aLab += *pLabel[j];
+ pDoc->SetString(nCol, nRow, nDestTab, aLab);
+ // Kategorie 12
+ SetFuncLine(nDataStartCol, nRow, nDestTab, nFuncMaskArr[j], SCSIZE_MAX, nSaveIndex, nRowIndex);
+ nRow++;
+ }
+ }
+ }
+ if ( nDataStartCol > 0 )
+ SetStyle(nCol, nSaveRow, nDataStartCol-1, nRow-1, PIVOT_STYLE_TITLE);
+ SetStyle(nDataStartCol, nSaveRow, nDestCol2, nRow-1, PIVOT_STYLE_RESULT);
+ SetFrameHor(nCol, nSaveRow, nDestCol2, nRow-1);
+ }
+ nSaveIndex = nRowIndex;
+ }
+ }
+ else if (nField < nColCount)
+ {
+ SCSIZE nCatCount = pColList[nField]->GetCount();
+ SetStyle(nCol, nRow, nCol, nRow+nCatCount-1, PIVOT_STYLE_CATEGORY);
+ SetFrame(nCol, nRow, nDestCol2, nRow+nCatCount-1);
+ for (SCSIZE i = 0; i < nCatCount; i++)
+ {
+ String aTmpStr = pColList[nField]->GetString(sal::static_int_cast<USHORT>(i));
+ if (!aTmpStr.Len()) aTmpStr = ScGlobal::GetRscString(STR_EMPTYDATA);
+
+ String aPutStr;
+ if (pColList[nField] == pDataList)
+ {
+ SCSIZE nFuncType = lcl_MaskToIndex( aDataArr[i].nFuncMask );
+ aPutStr = *pLabel[nFuncType];
+ aPutStr += ' ';
+ aPutStr += aTmpStr;
+ }
+ else
+ aPutStr += aTmpStr;
+
+ pDoc->SetString(nCol, nRow, nDestTab, aPutStr);
+ // Kategorie 13
+ SetDataLine(nCol + 1, nRow, nDestTab, nRowIndex);
+ nRowIndex++;
+ nRow++;
+
+ rProgress.SetState( nRow - nDestRow1 );
+ }
+ }
+}
+
+void ScPivot::RowToTable(SCSIZE nField, SCCOL& nCol)
+{
+ nRecCount++;
+ SCROW nRow = nDestRow1 + nFirstLine + nField + 1;
+ if (nRowCount == 0)
+ {
+ pColRef[nColIndex].nDataIndex = nDataIndex;
+ nColIndex++;
+ nDataIndex++;
+ return;
+ }
+
+ SCSIZE nDx;
+ if ((aRowArr[nRowCount -1].nCol == PIVOT_DATA_FIELD) && (nDataCount == 1))
+ nDx = 2;
+ else
+ nDx = 1;
+
+ if (nField < nRowCount - nDx)
+ {
+ for (USHORT i = 0; i < pRowList[nField]->GetCount(); i++)
+ {
+ String aStr = pRowList[nField]->GetString(i);
+ if (!aStr.Len()) aStr = ScGlobal::GetRscString(STR_EMPTYDATA);
+ pDoc->SetString(nCol, nRow, nDestTab, aStr);
+ // Kategorie 14
+ SCCOL nSaveCol = nCol;
+ RowToTable(nField + 1, nCol);
+ SetStyle(nSaveCol, nRow, nCol - 1, nRow, PIVOT_STYLE_CATEGORY);
+ SetFrame(nSaveCol, nRow, nCol - 1, nRow);
+ if (aRowArr[nField].nFuncCount > 0)
+ {
+ nSaveCol = nCol;
+ for (SCSIZE j=0; j<=PIVOT_MAXFUNC; j++) // incl. "auto"
+ {
+ if (aRowArr[nField].nFuncMask & nFuncMaskArr[j])
+ {
+ String aLab;
+ if (!bDataAtCol)
+ {
+ for (SCSIZE k=0; k < nDataCount; k++)
+ {
+ aLab = aStr;
+ SCSIZE nFuncType;
+ if ( j==PIVOT_MAXFUNC )
+ nFuncType = lcl_MaskToIndex( aDataArr[k].nFuncMask );
+ else
+ nFuncType = j;
+ aLab += ' ';
+ aLab += *pLabel[nFuncType];
+ aLab += ' ';
+ aLab += pDataList->GetString(sal::static_int_cast<USHORT>(k));
+ pDoc->SetString(nCol, nRow, nDestTab, aLab);
+ // Kategorie 15
+ pColRef[nColIndex].nDataIndex = PIVOT_FUNC_REF;
+ pColRef[nColIndex].nRecCount = nRecCount;
+ pColRef[nColIndex].nIndex = k;
+ pColRef[nColIndex].nFuncMask = nFuncMaskArr[j];
+ nColIndex++;
+ nCol++;
+ }
+ }
+ else
+ {
+ aLab = aStr;
+ aLab += ' ';
+ aLab += *pLabel[j];
+ pDoc->SetString(nCol, nRow, nDestTab, aLab);
+ // Kategorie 16
+ pColRef[nColIndex].nDataIndex = PIVOT_FUNC_REF;
+ pColRef[nColIndex].nRecCount = nRecCount;
+ pColRef[nColIndex].nIndex = SCSIZE_MAX;
+ pColRef[nColIndex].nFuncMask = nFuncMaskArr[j];
+ nColIndex++;
+ nCol++;
+ }
+ }
+ }
+ if ( nDataStartRow > 0 )
+ SetStyle(nSaveCol, nRow,
+ nCol-1, nDataStartRow-1, PIVOT_STYLE_TITLE);
+ SetStyle(nSaveCol, nDataStartRow, nCol-1, nDestRow2, PIVOT_STYLE_RESULT);
+ SetFrameVer(nSaveCol, nRow, nCol-1, nDestRow2);
+ }
+ }
+ }
+ else if (nField < nRowCount)
+ {
+ SCSIZE nCatCount = pRowList[nField]->GetCount();
+ SetStyle(nCol, nRow, sal::static_int_cast<SCCOL>(nCol+nCatCount-1), nRow, PIVOT_STYLE_CATEGORY);
+ SetFrame(nCol, nRow, sal::static_int_cast<SCCOL>(nCol+nCatCount-1), nDestRow2);
+ for (SCSIZE i = 0; i < nCatCount; i++)
+ {
+ String aTmpStr = pRowList[nField]->GetString(sal::static_int_cast<USHORT>(i));
+ if (!aTmpStr.Len()) aTmpStr = ScGlobal::GetRscString(STR_EMPTYDATA);
+
+ String aPutStr;
+ if (pRowList[nField] == pDataList)
+ {
+ SCSIZE nFuncType = lcl_MaskToIndex( aDataArr[i].nFuncMask );
+ aPutStr = *pLabel[nFuncType];
+ aPutStr += ' ';
+ aPutStr += aTmpStr;
+ }
+ else
+ aPutStr = aTmpStr;
+
+ pDoc->SetString(nCol, nRow, nDestTab, aPutStr);
+ // Kategorie 17
+ pColRef[nColIndex].nDataIndex = nDataIndex;
+ pColRef[nColIndex].nRecCount = nRecCount;
+ pColRef[nColIndex].nIndex = SCSIZE_MAX;
+ pColRef[nColIndex].nFuncMask = PIVOT_FUNC_NONE;
+ nColIndex++;
+ nDataIndex++;
+ nCol++;
+ }
+ }
+ nRecCount--;
+}
+
+SCROW ScPivot::GetCategoryRow( SCCOL nCol, SCROW nRow )
+{
+ SCROW nMinRow = nSrcRow1;
+ if (bHasHeader) ++nMinRow;
+ BOOL bFound = FALSE;
+ do
+ {
+ if ( !pDoc->HasData( nCol, nRow, nSrcTab ) && nRow>nMinRow )
+ --nRow;
+ else
+ bFound = TRUE;
+ }
+ while (!bFound);
+ return nRow;
+}
+
+#endif
+
diff --git a/sc/source/core/data/pivot2.cxx b/sc/source/core/data/pivot2.cxx
new file mode 100644
index 000000000000..20303f848b72
--- /dev/null
+++ b/sc/source/core/data/pivot2.cxx
@@ -0,0 +1,521 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: pivot2.cxx,v $
+ * $Revision: 1.14.32.3 $
+ *
+ * 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"
+
+
+
+#ifdef _MSC_VER
+#pragma optimize("",off)
+#endif
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/boxitem.hxx>
+#include <svx/wghtitem.hxx>
+#include <svx/algitem.hxx>
+#include <unotools/transliterationwrapper.hxx>
+
+#include "globstr.hrc"
+#include "subtotal.hxx"
+#include "rangeutl.hxx"
+#include "attrib.hxx"
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "document.hxx"
+#include "userlist.hxx"
+#include "pivot.hxx"
+#include "rechead.hxx"
+#include "formula/errorcodes.hxx" // fuer errNoValue
+#include "refupdat.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+
+using ::com::sun::star::sheet::DataPilotFieldReference;
+
+// STATIC DATA -----------------------------------------------------------
+
+#if OLD_PIVOT_IMPLEMENTATION
+//--------------------------------------------------------------------------------------------------
+// Hilfsmethoden von ScPivot
+//--------------------------------------------------------------------------------------------------
+
+void ScPivot::SetFrame(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, USHORT nWidth)
+{
+ if (pDoc->pTab[nDestTab])
+ {
+ SvxBorderLine aLine;
+ aLine.SetOutWidth(nWidth);
+ SvxBoxItem aBox( ATTR_BORDER );
+ aBox.SetLine(&aLine, BOX_LINE_LEFT);
+ aBox.SetLine(&aLine, BOX_LINE_TOP);
+ aBox.SetLine(&aLine, BOX_LINE_RIGHT);
+ aBox.SetLine(&aLine, BOX_LINE_BOTTOM);
+ SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
+ aBoxInfo.SetValid(VALID_HORI,FALSE);
+ aBoxInfo.SetValid(VALID_VERT,FALSE);
+ aBoxInfo.SetValid(VALID_DISTANCE,FALSE);
+ pDoc->pTab[nDestTab]->ApplyBlockFrame(&aBox, &aBoxInfo, nCol1, nRow1, nCol2, nRow2);
+ }
+}
+
+void ScPivot::SetFrameHor(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
+{
+ if (pDoc->pTab[nDestTab])
+ {
+ SvxBorderLine aLine;
+ aLine.SetOutWidth(20);
+ SvxBoxItem aBox( ATTR_BORDER );
+ aBox.SetLine(&aLine, BOX_LINE_LEFT);
+ aBox.SetLine(&aLine, BOX_LINE_TOP);
+ aBox.SetLine(&aLine, BOX_LINE_RIGHT);
+ aBox.SetLine(&aLine, BOX_LINE_BOTTOM);
+ SvxBoxInfoItem aBoxInfo(ATTR_BORDER_INNER);
+ aBoxInfo.SetValid(VALID_VERT,FALSE);
+ aBoxInfo.SetValid(VALID_DISTANCE,FALSE);
+ aBoxInfo.SetLine(&aLine, BOXINFO_LINE_HORI);
+ pDoc->pTab[nDestTab]->ApplyBlockFrame(&aBox, &aBoxInfo, nCol1, nRow1, nCol2, nRow2);
+ }
+}
+
+void ScPivot::SetFrameVer(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
+{
+ if (pDoc->pTab[nDestTab])
+ {
+ SvxBorderLine aLine;
+ aLine.SetOutWidth(20);
+ SvxBoxItem aBox( ATTR_BORDER );
+ aBox.SetLine(&aLine, BOX_LINE_LEFT);
+ aBox.SetLine(&aLine, BOX_LINE_TOP);
+ aBox.SetLine(&aLine, BOX_LINE_RIGHT);
+ aBox.SetLine(&aLine, BOX_LINE_BOTTOM);
+ SvxBoxInfoItem aBoxInfo( ATTR_BORDER_INNER );
+ aBoxInfo.SetValid(VALID_HORI,FALSE);
+ aBoxInfo.SetValid(VALID_DISTANCE,FALSE);
+ aBoxInfo.SetLine(&aLine, BOXINFO_LINE_VERT);
+ pDoc->pTab[nDestTab]->ApplyBlockFrame(&aBox, &aBoxInfo, nCol1, nRow1, nCol2, nRow2);
+ }
+}
+
+void ScPivot::SetFontBold(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
+{
+ if (pDoc->pTab[nDestTab])
+ {
+ ScPatternAttr aPattern( pDoc->GetPool() );
+ aPattern.GetItemSet().Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
+ pDoc->pTab[nDestTab]->ApplyPatternArea(nCol1, nRow1, nCol2, nRow2, aPattern);
+ }
+}
+
+void ScPivot::SetJustifyLeft(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
+{
+ if (pDoc->pTab[nDestTab])
+ {
+ ScPatternAttr aPattern( pDoc->GetPool() );
+ aPattern.GetItemSet().Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
+ pDoc->pTab[nDestTab]->ApplyPatternArea(nCol1, nRow1, nCol2, nRow2, aPattern);
+ }
+}
+
+void ScPivot::SetJustifyRight(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
+{
+ if (pDoc->pTab[nDestTab])
+ {
+ ScPatternAttr aPattern( pDoc->GetPool() );
+ aPattern.GetItemSet().Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_RIGHT, ATTR_HOR_JUSTIFY ) );
+ pDoc->pTab[nDestTab]->ApplyPatternArea(nCol1, nRow1, nCol2, nRow2, aPattern);
+ }
+}
+
+void ScPivot::SetButton(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
+{
+ if (pDoc->pTab[nDestTab])
+ {
+ ScPatternAttr aPattern( pDoc->GetPool() );
+ aPattern.GetItemSet().Put( ScMergeFlagAttr(SC_MF_BUTTON) );
+ pDoc->pTab[nDestTab]->ApplyPatternArea(nCol1, nRow1, nCol2, nRow2, aPattern);
+ }
+}
+
+void ScPivot::SetStyle(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, USHORT nId)
+{
+ if ( nCol1 > nCol2 || nRow1 > nRow2 )
+ return; // Falls Bereiche leer sind
+
+ USHORT nStringId = 0;
+ switch (nId)
+ {
+ case PIVOT_STYLE_INNER: nStringId = STR_PIVOT_STYLE_INNER; break;
+ case PIVOT_STYLE_RESULT: nStringId = STR_PIVOT_STYLE_RESULT; break;
+ case PIVOT_STYLE_CATEGORY: nStringId = STR_PIVOT_STYLE_CATEGORY; break;
+ case PIVOT_STYLE_TITLE: nStringId = STR_PIVOT_STYLE_TITLE; break;
+ case PIVOT_STYLE_FIELDNAME: nStringId = STR_PIVOT_STYLE_FIELDNAME; break;
+ case PIVOT_STYLE_TOP: nStringId = STR_PIVOT_STYLE_TOP; break;
+ default:
+ DBG_ERROR("falsche ID bei ScPivot::SetStyle");
+ return;
+ }
+ String aStyleName = ScGlobal::GetRscString(nStringId);
+
+ ScStyleSheetPool* pStlPool = pDoc->GetStyleSheetPool();
+ ScStyleSheet* pStyle = (ScStyleSheet*) pStlPool->Find( aStyleName, SFX_STYLE_FAMILY_PARA );
+ if (!pStyle)
+ {
+ // neu anlegen
+
+ pStyle = (ScStyleSheet*) &pStlPool->Make( aStyleName, SFX_STYLE_FAMILY_PARA,
+ SFXSTYLEBIT_USERDEF );
+ pStyle->SetParent( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
+ SfxItemSet& rSet = pStyle->GetItemSet();
+ if ( nId==PIVOT_STYLE_RESULT || nId==PIVOT_STYLE_TITLE )
+ rSet.Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
+ if ( nId==PIVOT_STYLE_CATEGORY || nId==PIVOT_STYLE_TITLE )
+ rSet.Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_LEFT, ATTR_HOR_JUSTIFY ) );
+ }
+
+ pDoc->pTab[nDestTab]->ApplyStyleArea( nCol1, nRow1, nCol2, nRow2, *pStyle );
+}
+
+void ScPivot::SetValue(SCCOL nCol, SCROW nRow, const SubTotal& rTotal, USHORT nFunc)
+{
+ if ( rTotal.Valid( nFunc ) == 1)
+ pDoc->SetValue(nCol, nRow, nDestTab, rTotal.Result( nFunc ));
+ else if ( rTotal.Valid( nFunc ) == 0)
+ pDoc->SetError(nCol, nRow, nDestTab, errNoValue);
+}
+
+//--------------------------------------------------------------------------------------------------
+
+void ScPivot::GetParam( ScPivotParam& rParam, ScQueryParam& rQuery, ScArea& rSrcArea ) const
+{
+ SCSIZE nCount;
+ SCCOL nDummyCol;
+ SCROW nDummyRow;
+ GetDestArea( rParam.nCol,rParam.nRow, nDummyCol,nDummyRow, rParam.nTab );
+
+ // Row und Col in der Bedeutung vertauscht:
+ GetRowFields( rParam.aColArr, nCount );
+ rParam.nColCount = nCount;
+ GetColFields( rParam.aRowArr, nCount );
+ rParam.nRowCount = nCount;
+ GetDataFields( rParam.aDataArr, nCount );
+ rParam.nDataCount = nCount;
+
+ rParam.bIgnoreEmptyRows = GetIgnoreEmpty();
+ rParam.bDetectCategories = GetDetectCat();
+ rParam.bMakeTotalCol = GetMakeTotalCol();
+ rParam.bMakeTotalRow = GetMakeTotalRow();
+
+ GetQuery(rQuery);
+ GetSrcArea( rSrcArea.nColStart, rSrcArea.nRowStart,
+ rSrcArea.nColEnd, rSrcArea.nRowEnd, rSrcArea.nTab );
+}
+
+void ScPivot::SetParam( const ScPivotParam& rParam, const ScQueryParam& rQuery,
+ const ScArea& rSrcArea )
+{
+ SetQuery( rQuery );
+ SetHeader( TRUE );
+ SetSrcArea( rSrcArea.nColStart, rSrcArea.nRowStart,
+ rSrcArea.nColEnd, rSrcArea.nRowEnd, rSrcArea.nTab );
+ SetDestPos( rParam.nCol, rParam.nRow, rParam.nTab );
+ SetIgnoreEmpty( rParam.bIgnoreEmptyRows );
+ SetDetectCat( rParam.bDetectCategories );
+ SetMakeTotalCol( rParam.bMakeTotalCol );
+ SetMakeTotalRow( rParam.bMakeTotalRow );
+
+ // Row und Col in der Bedeutung vertauscht:
+ SetRowFields( rParam.aColArr, rParam.nColCount );
+ SetColFields( rParam.aRowArr, rParam.nRowCount );
+ SetDataFields( rParam.aDataArr, rParam.nDataCount );
+}
+
+ScDataObject* ScPivot::Clone() const
+{
+ return new ScPivot(*this);
+}
+
+//--------------------------------------------------------------------------------------------------
+// PivotScStrCollection
+//--------------------------------------------------------------------------------------------------
+
+ScDataObject* PivotScStrCollection::Clone() const
+{
+ return new PivotScStrCollection(*this);
+}
+
+short PivotScStrCollection::Compare(ScDataObject* pKey1, ScDataObject* pKey2) const
+{
+ DBG_ASSERT(pKey1&&pKey2,"0-Zeiger bei PivotScStrCollection::Compare");
+
+ short nResult = 0;
+
+ TypedStrData& rData1 = (TypedStrData&)*pKey1;
+ TypedStrData& rData2 = (TypedStrData&)*pKey2;
+
+ if ( rData1.nStrType > rData2.nStrType )
+ nResult = 1;
+ else if ( rData1.nStrType < rData2.nStrType )
+ nResult = -1;
+ else if ( !rData1.nStrType /* && !rData2.nStrType */ )
+ {
+ // Zahlen vergleichen:
+
+ if ( rData1.nValue == rData2.nValue )
+ nResult = 0;
+ else if ( rData1.nValue < rData2.nValue )
+ nResult = -1;
+ else
+ nResult = 1;
+ }
+ else /* if ( rData1.nStrType && rData2.nStrType ) */
+ {
+ // Strings vergleichen:
+
+ if (pUserData)
+ nResult = sal::static_int_cast<short>(pUserData->ICompare(rData1.aStrValue, rData2.aStrValue));
+ else
+ {
+ nResult = (short) ScGlobal::pTransliteration->compareString(
+ rData1.aStrValue, rData2.aStrValue );
+ }
+ }
+
+ return nResult;
+}
+
+USHORT PivotScStrCollection::GetIndex(TypedStrData* pData) const
+{
+ USHORT nIndex = 0;
+ if (!Search(pData, nIndex))
+ nIndex = 0;
+ return nIndex;
+}
+
+//--------------------------------------------------------------------------------------------------
+// PivotCollection
+//--------------------------------------------------------------------------------------------------
+
+String ScPivotCollection::CreateNewName( USHORT nMin ) const
+{
+ String aBase( RTL_CONSTASCII_USTRINGPARAM("DataPilot") );
+ //! from Resource?
+
+ for (USHORT nAdd=0; nAdd<=nCount; nAdd++) // nCount+1 Versuche
+ {
+ String aNewName = aBase;
+ aNewName += String::CreateFromInt32( nMin + nAdd );
+ BOOL bFound = FALSE;
+ for (USHORT i=0; i<nCount && !bFound; i++)
+ if (((ScPivot*)pItems[i])->GetName() == aNewName)
+ bFound = TRUE;
+ if (!bFound)
+ return aNewName; // freien Namen gefunden
+ }
+ return String(); // sollte nicht vorkommen
+}
+
+ScPivot* ScPivotCollection::GetPivotAtCursor(SCCOL nCol, SCROW nRow, SCTAB nTab) const
+{
+ if (pItems)
+ {
+ for (USHORT i = 0; i < nCount; i++)
+ if (((ScPivot*)pItems[i])->IsPivotAtCursor(nCol, nRow, nTab))
+ {
+ return (ScPivot*)pItems[i];
+ }
+ }
+ return NULL;
+}
+
+BOOL ScPivotCollection::Load(SvStream& rStream)
+{
+ BOOL bSuccess = TRUE;
+ USHORT nNewCount, i;
+ FreeAll();
+
+ ScMultipleReadHeader aHdr( rStream );
+
+ rStream >> nNewCount;
+ for (i=0; i<nNewCount && bSuccess; i++)
+ {
+ ScPivot* pPivot = new ScPivot( pDoc );
+ if (pPivot)
+ {
+ bSuccess = pPivot->Load(rStream, aHdr);
+ Insert( pPivot );
+ }
+ else
+ bSuccess = FALSE;
+ }
+
+ // fuer alte Dateien: eindeutige Namen vergeben
+
+ if (bSuccess)
+ for (i=0; i<nCount; i++)
+ if (!((const ScPivot*)At(i))->GetName().Len())
+ ((ScPivot*)At(i))->SetName( CreateNewName() );
+
+ return bSuccess;
+}
+
+BOOL ScPivotCollection::Store(SvStream& rStream) const
+{
+ BOOL bSuccess = TRUE;
+
+ ScMultipleWriteHeader aHdr( rStream );
+
+ rStream << nCount;
+
+ for (USHORT i=0; i<nCount && bSuccess; i++)
+ bSuccess = ((const ScPivot*)At(i))->Store( rStream, aHdr );
+
+ return bSuccess;
+}
+
+void ScPivotCollection::UpdateReference(UpdateRefMode eUpdateRefMode,
+ SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ for (USHORT i=0; i<nCount; i++)
+ {
+ SCCOL theCol1;
+ SCROW theRow1;
+ SCTAB theTab1;
+ SCCOL theCol2;
+ SCROW theRow2;
+ SCTAB theTab2;
+ ScRefUpdateRes eRes;
+ ScPivot* pPivot = (ScPivot*)pItems[i];
+
+ // Source
+
+ pPivot->GetSrcArea( theCol1, theRow1, theCol2, theRow2, theTab1 );
+ theTab2 = theTab1;
+
+ eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
+ theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
+
+ if (eRes != UR_NOTHING)
+ pPivot->MoveSrcArea( theCol1, theRow1, theTab1 );
+
+ // Dest
+
+ pPivot->GetDestArea( theCol1, theRow1, theCol2, theRow2, theTab1 );
+ theTab2 = theTab1;
+
+ eRes = ScRefUpdate::Update( pDoc, eUpdateRefMode,
+ nCol1,nRow1,nTab1, nCol2,nRow2,nTab2, nDx,nDy,nDz,
+ theCol1,theRow1,theTab1, theCol2,theRow2,theTab2 );
+
+ if (eRes != UR_NOTHING)
+ pPivot->MoveDestArea( theCol1, theRow1, theTab1 );
+ }
+}
+
+void ScPivotCollection::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
+{
+ // nur Quell-Bereich
+
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ScPivot* pPivot = (ScPivot*)pItems[i];
+ ScRange aSrc = pPivot->GetSrcArea();
+ ScRefUpdateRes eRes = ScRefUpdate::DoGrow( rArea, nGrowX, nGrowY, aSrc );
+ if (eRes != UR_NOTHING)
+ pPivot->ExtendSrcArea( aSrc.aEnd.Col(), aSrc.aEnd.Row() );
+ }
+}
+
+BOOL ScPivotCollection::operator==(const ScPivotCollection& rCmp) const
+{
+ if (nCount != rCmp.nCount)
+ return FALSE;
+
+ if (!nCount)
+ return TRUE; // beide leer - nicht erst die Param's anlegen!
+
+ ScPivotParam aMyParam, aCmpParam;
+ ScQueryParam aMyQuery, aCmpQuery;
+ ScArea aMyArea, aCmpArea;
+
+ for (USHORT i=0; i<nCount; i++)
+ {
+ ScPivot* pMyPivot = (ScPivot*)pItems[i];
+ pMyPivot->GetParam( aMyParam, aMyQuery, aMyArea );
+ ScPivot* pCmpPivot = (ScPivot*)rCmp.pItems[i];
+ pCmpPivot->GetParam( aCmpParam, aCmpQuery, aCmpArea );
+ if (!( aMyArea==aCmpArea && aMyParam==aCmpParam && aMyQuery==aCmpQuery ))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ScDataObject* ScPivotCollection::Clone() const
+{
+ return new ScPivotCollection(*this);
+}
+
+#endif
+
+// ============================================================================
+
+LabelData::LabelData( const String& rName, short nCol, bool bIsValue ) :
+ maName( rName ),
+ mnCol( nCol ),
+ mnFuncMask( PIVOT_FUNC_NONE ),
+ mnUsedHier( 0 ),
+ mbShowAll( false ),
+ mbIsValue( bIsValue )
+{
+}
+
+// ============================================================================
+
+ScDPFuncData::ScDPFuncData( short nCol, USHORT nFuncMask ) :
+ mnCol( nCol ),
+ mnFuncMask( nFuncMask )
+{
+}
+
+ScDPFuncData::ScDPFuncData( short nCol, USHORT nFuncMask, const DataPilotFieldReference& rFieldRef ) :
+ mnCol( nCol ),
+ mnFuncMask( nFuncMask ),
+ maFieldRef( rFieldRef )
+{
+}
+
+// ============================================================================
+
diff --git a/sc/source/core/data/poolhelp.cxx b/sc/source/core/data/poolhelp.cxx
new file mode 100644
index 000000000000..0121eca685e4
--- /dev/null
+++ b/sc/source/core/data/poolhelp.cxx
@@ -0,0 +1,89 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: poolhelp.cxx,v $
+ * $Revision: 1.8 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <svtools/zforlist.hxx>
+#include <svx/editeng.hxx>
+
+#include "poolhelp.hxx"
+#include "document.hxx"
+#include "docpool.hxx"
+#include "stlpool.hxx"
+
+// -----------------------------------------------------------------------
+
+ScPoolHelper::ScPoolHelper( ScDocument* pSourceDoc )
+{
+ DBG_ASSERT( pSourceDoc, "ScPoolHelper: no document" );
+
+ pDocPool = new ScDocumentPool;
+ pDocPool->FreezeIdRanges();
+
+ mxStylePool = new ScStyleSheetPool( *pDocPool, pSourceDoc );
+
+ pFormTable = new SvNumberFormatter( pSourceDoc->GetServiceManager(), ScGlobal::eLnge );
+ pFormTable->SetColorLink( LINK( pSourceDoc, ScDocument, GetUserDefinedColor ) );
+ pFormTable->SetEvalDateFormat( NF_EVALDATEFORMAT_INTL_FORMAT );
+
+ pEditPool = EditEngine::CreatePool();
+ pEditPool->SetDefaultMetric( SFX_MAPUNIT_100TH_MM );
+ pEditPool->FreezeIdRanges();
+ pEditPool->SetFileFormatVersion( SOFFICE_FILEFORMAT_50 ); // used in ScGlobal::EETextObjEqual
+
+ pEnginePool = EditEngine::CreatePool();
+ pEnginePool->SetDefaultMetric( SFX_MAPUNIT_100TH_MM );
+ pEnginePool->FreezeIdRanges();
+}
+
+ScPoolHelper::~ScPoolHelper()
+{
+ SfxItemPool::Free(pEnginePool);
+ SfxItemPool::Free(pEditPool);
+ delete pFormTable;
+ mxStylePool.clear();
+ SfxItemPool::Free(pDocPool);
+}
+
+void ScPoolHelper::SourceDocumentGone()
+{
+ // reset all pointers to the source document
+ mxStylePool->SetDocument( NULL );
+ pFormTable->SetColorLink( Link() );
+}
+
+// -----------------------------------------------------------------------
+
+
diff --git a/sc/source/core/data/postit.cxx b/sc/source/core/data/postit.cxx
new file mode 100644
index 000000000000..068ec3ade5e5
--- /dev/null
+++ b/sc/source/core/data/postit.cxx
@@ -0,0 +1,660 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: postit.cxx,v $
+ * $Revision: 1.12.54.11 $
+ *
+ * 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 "postit.hxx"
+
+#include <svtools/useroptions.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/outlobj.hxx>
+#include <svx/editobj.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+
+#include "scitems.hxx"
+#include <svx/xlnstit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnstcit.hxx>
+#include <svx/sxcecitm.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/sdshitm.hxx>
+#include <svx/sdsxyitm.hxx>
+
+#include "document.hxx"
+#include "docpool.hxx"
+#include "patattr.hxx"
+#include "cell.hxx"
+#include "drwlayer.hxx"
+#include "userdat.hxx"
+#include "detfunc.hxx"
+
+// ============================================================================
+
+namespace {
+
+const long SC_NOTECAPTION_WIDTH = 2900; /// Default width of note caption textbox.
+const long SC_NOTECAPTION_MAXWIDTH_TEMP = 12000; /// Maximum width of temporary note caption textbox.
+const long SC_NOTECAPTION_HEIGHT = 1800; /// Default height of note caption textbox.
+const long SC_NOTECAPTION_CELLDIST = 600; /// Default distance of note captions to border of anchor cell.
+const long SC_NOTECAPTION_OFFSET_Y = -1500; /// Default Y offset of note captions to top border of anchor cell.
+const long SC_NOTECAPTION_OFFSET_X = 1500; /// Default X offset of note captions to left border of anchor cell.
+const long SC_NOTECAPTION_BORDERDIST_TEMP = 100; /// Distance of temporary note captions to visible sheet area.
+
+// ----------------------------------------------------------------------------
+
+class ScCaptionCreator
+{
+public:
+ /** Create a new caption. The caption will not be inserted into the document. */
+ explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bShown, bool bTailFront );
+ /** Manipulate an existing caption. */
+ explicit ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption );
+
+ /** Returns the caption drawing obejct. */
+ inline SdrCaptionObj* GetCaption() { return mpCaption; }
+
+ /** Moves the caption inside the passed rectangle. Uses page area if 0 is passed. */
+ void FitCaptionToRect( const Rectangle* pVisRect = 0 );
+ /** Places the passed caption inside the passed rectangle, tries to keep the cell rectangle uncovered. Uses page area if 0 is passed. */
+ void AutoPlaceCaption( const Rectangle* pVisRect = 0 );
+ /** Updates caption tail and textbox according to current cell position. Uses page area if 0 is passed. */
+ void UpdateCaptionPos( const Rectangle* pVisRect = 0 );
+ /** Sets all default formatting attributes to the caption object. */
+ void SetDefaultItems();
+ /** Updates caption itemset according to the passed item set while removing shadow items. */
+ void SetCaptionItems( const SfxItemSet& rItemSet );
+
+private:
+ /** Initializes all members. */
+ void Initialize();
+ /** Returns the passed rectangle if existing, page rectangle otherwise. */
+ inline const Rectangle& GetVisRect( const Rectangle* pVisRect ) const { return pVisRect ? *pVisRect : maPageRect; }
+ /** Calculates the caption tail position according to current cell position. */
+ Point CalcTailPos( bool bTailFront );
+
+private:
+ ScDocument& mrDoc;
+ ScAddress maPos;
+ SdrCaptionObj* mpCaption;
+ Rectangle maPageRect;
+ Rectangle maCellRect;
+ bool mbNegPage;
+};
+
+// ----------------------------------------------------------------------------
+
+ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, bool bShown, bool bTailFront ) :
+ mrDoc( rDoc ),
+ maPos( rPos ),
+ mpCaption( 0 )
+{
+ Initialize();
+
+ // create the caption drawing object
+ Rectangle aTextRect( Point( 0 , 0 ), Size( SC_NOTECAPTION_WIDTH, SC_NOTECAPTION_HEIGHT ) );
+ Point aTailPos = CalcTailPos( bTailFront );
+ mpCaption = new SdrCaptionObj( aTextRect, aTailPos );
+
+ // basic settings
+ ScDrawLayer::SetAnchor( mpCaption, SCA_PAGE );
+ mpCaption->SetLayer( bShown ? SC_LAYER_INTERN : SC_LAYER_HIDDEN );
+ mpCaption->SetFixedTail();
+ mpCaption->SetSpecialTextBoxShadow();
+}
+
+ScCaptionCreator::ScCaptionCreator( ScDocument& rDoc, const ScAddress& rPos, SdrCaptionObj& rCaption ) :
+ mrDoc( rDoc ),
+ maPos( rPos ),
+ mpCaption( &rCaption )
+{
+ Initialize();
+}
+
+void ScCaptionCreator::FitCaptionToRect( const Rectangle* pVisRect )
+{
+ const Rectangle& rVisRect = GetVisRect( pVisRect );
+
+ // tail position
+ Point aTailPos = mpCaption->GetTailPos();
+ aTailPos.X() = ::std::max( ::std::min( aTailPos.X(), rVisRect.Right() ), rVisRect.Left() );
+ aTailPos.Y() = ::std::max( ::std::min( aTailPos.Y(), rVisRect.Bottom() ), rVisRect.Top() );
+ mpCaption->SetTailPos( aTailPos );
+
+ // caption rectangle
+ Rectangle aCaptRect = mpCaption->GetLogicRect();
+ Point aCaptPos = aCaptRect.TopLeft();
+ // move textbox inside right border of visible area
+ aCaptPos.X() = ::std::min< long >( aCaptPos.X(), rVisRect.Right() - aCaptRect.GetWidth() );
+ // move textbox inside left border of visible area (this may move it outside on right side again)
+ aCaptPos.X() = ::std::max< long >( aCaptPos.X(), rVisRect.Left() );
+ // move textbox inside bottom border of visible area
+ aCaptPos.Y() = ::std::min< long >( aCaptPos.Y(), rVisRect.Bottom() - aCaptRect.GetHeight() );
+ // move textbox inside top border of visible area (this may move it outside on bottom side again)
+ aCaptPos.Y() = ::std::max< long >( aCaptPos.Y(), rVisRect.Top() );
+ // update caption
+ aCaptRect.SetPos( aCaptPos );
+ mpCaption->SetLogicRect( aCaptRect );
+}
+
+void ScCaptionCreator::AutoPlaceCaption( const Rectangle* pVisRect )
+{
+ const Rectangle& rVisRect = GetVisRect( pVisRect );
+
+ // caption rectangle
+ Rectangle aCaptRect = mpCaption->GetLogicRect();
+ long nWidth = aCaptRect.GetWidth();
+ long nHeight = aCaptRect.GetHeight();
+
+ // n***Space contains available space between border of visible area and cell
+ long nLeftSpace = maCellRect.Left() - rVisRect.Left() + 1;
+ long nRightSpace = rVisRect.Right() - maCellRect.Right() + 1;
+ long nTopSpace = maCellRect.Top() - rVisRect.Top() + 1;
+ long nBottomSpace = rVisRect.Bottom() - maCellRect.Bottom() + 1;
+
+ // nNeeded*** contains textbox dimensions plus needed distances to cell or border of visible area
+ long nNeededSpaceX = nWidth + SC_NOTECAPTION_CELLDIST;
+ long nNeededSpaceY = nHeight + SC_NOTECAPTION_CELLDIST;
+
+ // bFitsWidth*** == true means width of textbox fits into horizontal free space of visible area
+ bool bFitsWidthLeft = nNeededSpaceX <= nLeftSpace; // text box width fits into the width left of cell
+ bool bFitsWidthRight = nNeededSpaceX <= nRightSpace; // text box width fits into the width right of cell
+ bool bFitsWidth = nWidth <= rVisRect.GetWidth(); // text box width fits into width of visible area
+
+ // bFitsHeight*** == true means height of textbox fits into vertical free space of visible area
+ bool bFitsHeightTop = nNeededSpaceY <= nTopSpace; // text box height fits into the height above cell
+ bool bFitsHeightBottom = nNeededSpaceY <= nBottomSpace; // text box height fits into the height below cell
+ bool bFitsHeight = nHeight <= rVisRect.GetHeight(); // text box height fits into height of visible area
+
+ // bFits*** == true means the textbox fits completely into free space of visible area
+ bool bFitsLeft = bFitsWidthLeft && bFitsHeight;
+ bool bFitsRight = bFitsWidthRight && bFitsHeight;
+ bool bFitsTop = bFitsWidth && bFitsHeightTop;
+ bool bFitsBottom = bFitsWidth && bFitsHeightBottom;
+
+ Point aCaptPos;
+ // use left/right placement if possible, or if top/bottom placement not possible
+ if( bFitsLeft || bFitsRight || (!bFitsTop && !bFitsBottom) )
+ {
+ // prefer left in RTL sheet and right in LTR sheets
+ bool bPreferLeft = bFitsLeft && (mbNegPage || !bFitsRight);
+ bool bPreferRight = bFitsRight && (!mbNegPage || !bFitsLeft);
+ // move to left, if left is preferred, or if neither left nor right fit and there is more space to the left
+ if( bPreferLeft || (!bPreferRight && (nLeftSpace > nRightSpace)) )
+ aCaptPos.X() = maCellRect.Left() - SC_NOTECAPTION_CELLDIST - nWidth;
+ else // to right
+ aCaptPos.X() = maCellRect.Right() + SC_NOTECAPTION_CELLDIST;
+ // Y position according to top cell border
+ aCaptPos.Y() = maCellRect.Top() + SC_NOTECAPTION_OFFSET_Y;
+ }
+ else // top or bottom placement
+ {
+ // X position
+ aCaptPos.X() = maCellRect.Left() + SC_NOTECAPTION_OFFSET_X;
+ // top placement, if possible
+ if( bFitsTop )
+ aCaptPos.Y() = maCellRect.Top() - SC_NOTECAPTION_CELLDIST - nHeight;
+ else // bottom placement
+ aCaptPos.Y() = maCellRect.Bottom() + SC_NOTECAPTION_CELLDIST;
+ }
+
+ // update textbox position in note caption object
+ aCaptRect.SetPos( aCaptPos );
+ mpCaption->SetLogicRect( aCaptRect );
+ FitCaptionToRect( pVisRect );
+}
+
+void ScCaptionCreator::UpdateCaptionPos( const Rectangle* pVisRect )
+{
+ ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer();
+
+ // update caption position
+ const Point& rOldTailPos = mpCaption->GetTailPos();
+ Point aTailPos = CalcTailPos( false );
+ if( rOldTailPos != aTailPos )
+ {
+ // create drawing undo action
+ if( pDrawLayer && pDrawLayer->IsRecording() )
+ pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoGeoObject( *mpCaption ) );
+ // calculate new caption rectangle (#i98141# handle LTR<->RTL switch correctly)
+ Rectangle aCaptRect = mpCaption->GetLogicRect();
+ long nDiffX = (rOldTailPos.X() >= 0) ? (aCaptRect.Left() - rOldTailPos.X()) : (rOldTailPos.X() - aCaptRect.Right());
+ if( mbNegPage ) nDiffX = -nDiffX - aCaptRect.GetWidth();
+ long nDiffY = aCaptRect.Top() - rOldTailPos.Y();
+ aCaptRect.SetPos( aTailPos + Point( nDiffX, nDiffY ) );
+ // set new tail position and caption rectangle
+ mpCaption->SetTailPos( aTailPos );
+ mpCaption->SetLogicRect( aCaptRect );
+ // fit caption into draw page
+ FitCaptionToRect( pVisRect );
+ }
+
+ // update cell position in caption user data
+ ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( mpCaption, maPos.Tab() );
+ if( pCaptData && (maPos != pCaptData->maStart) )
+ {
+ // create drawing undo action
+ if( pDrawLayer && pDrawLayer->IsRecording() )
+ pDrawLayer->AddCalcUndo( new ScUndoObjData( mpCaption, pCaptData->maStart, pCaptData->maEnd, maPos, pCaptData->maEnd ) );
+ // set new position
+ pCaptData->maStart = maPos;
+ }
+}
+
+void ScCaptionCreator::SetDefaultItems()
+{
+ SfxItemSet aItemSet = mpCaption->GetMergedItemSet();
+
+ // caption tail arrow
+ ::basegfx::B2DPolygon aTriangle;
+ aTriangle.append( ::basegfx::B2DPoint( 10.0, 0.0 ) );
+ aTriangle.append( ::basegfx::B2DPoint( 0.0, 30.0 ) );
+ aTriangle.append( ::basegfx::B2DPoint( 20.0, 30.0 ) );
+ aTriangle.setClosed( true );
+ /* #99319# Line ends are now created with an empty name. The
+ checkForUniqueItem() method then finds a unique name for the item's
+ value. */
+ aItemSet.Put( XLineStartItem( String::EmptyString(), ::basegfx::B2DPolyPolygon( aTriangle ) ) );
+ aItemSet.Put( XLineStartWidthItem( 200 ) );
+ aItemSet.Put( XLineStartCenterItem( FALSE ) );
+ aItemSet.Put( XFillStyleItem( XFILL_SOLID ) );
+ aItemSet.Put( XFillColorItem( String::EmptyString(), ScDetectiveFunc::GetCommentColor() ) );
+ aItemSet.Put( SdrCaptionEscDirItem( SDRCAPT_ESCBESTFIT ) );
+
+ // shadow
+ /* SdrShadowItem has FALSE, instead the shadow is set for the
+ rectangle only with SetSpecialTextBoxShadow when the object is
+ created (item must be set to adjust objects from older files). */
+ aItemSet.Put( SdrShadowItem( FALSE ) );
+ aItemSet.Put( SdrShadowXDistItem( 100 ) );
+ aItemSet.Put( SdrShadowYDistItem( 100 ) );
+
+ // text attributes
+ aItemSet.Put( SdrTextLeftDistItem( 100 ) );
+ aItemSet.Put( SdrTextRightDistItem( 100 ) );
+ aItemSet.Put( SdrTextUpperDistItem( 100 ) );
+ aItemSet.Put( SdrTextLowerDistItem( 100 ) );
+ aItemSet.Put( SdrTextAutoGrowWidthItem( FALSE ) );
+ aItemSet.Put( SdrTextAutoGrowHeightItem( TRUE ) );
+ // #78943# use the default cell style to be able to modify the caption font
+ const ScPatternAttr& rDefPattern = static_cast< const ScPatternAttr& >( mrDoc.GetPool()->GetDefaultItem( ATTR_PATTERN ) );
+ rDefPattern.FillEditItemSet( &aItemSet );
+
+ mpCaption->SetMergedItemSet( aItemSet );
+}
+
+void ScCaptionCreator::SetCaptionItems( const SfxItemSet& rItemSet )
+{
+ // copy all items
+ mpCaption->SetMergedItemSet( rItemSet );
+ // reset shadow items
+ mpCaption->SetMergedItem( SdrShadowItem( FALSE ) );
+ mpCaption->SetMergedItem( SdrShadowXDistItem( 100 ) );
+ mpCaption->SetMergedItem( SdrShadowYDistItem( 100 ) );
+ mpCaption->SetSpecialTextBoxShadow();
+}
+
+void ScCaptionCreator::Initialize()
+{
+ maCellRect = ScDrawLayer::GetCellRect( mrDoc, maPos, true );
+ mbNegPage = mrDoc.IsNegativePage( maPos.Tab() );
+
+ if( ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer() )
+ {
+ if( SdrPage* pPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( maPos.Tab() ) ) )
+ {
+ maPageRect = Rectangle( Point( 0, 0 ), pPage->GetSize() );
+ /* #i98141# SdrPage::GetSize() returns negative width in RTL mode.
+ The call to Rectangle::Adjust() orders left/right coordinate
+ accordingly. */
+ maPageRect.Justify();
+ }
+ }
+}
+
+Point ScCaptionCreator::CalcTailPos( bool bTailFront )
+{
+ // tail position
+ bool bTailLeft = bTailFront != mbNegPage;
+ Point aTailPos = bTailLeft ? maCellRect.TopLeft() : maCellRect.TopRight();
+ // move caption point 1/10 mm inside cell
+ if( bTailLeft ) aTailPos.X() += 10; else aTailPos.X() -= 10;
+ aTailPos.Y() += 10;
+ return aTailPos;
+}
+
+} // namespace
+
+// ============================================================================
+
+ScNoteData::ScNoteData( bool bShown ) :
+ mpCaption( 0 ),
+ mbShown( bShown )
+{
+}
+
+// ============================================================================
+
+ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, bool bShown ) :
+ mrDoc( rDoc ),
+ maNoteData( bShown )
+{
+ AutoStamp();
+ CreateCaption( rPos );
+}
+
+ScPostIt::ScPostIt( ScDocument& rDoc, const ScAddress& rPos, const ScPostIt& rNote ) :
+ mrDoc( rDoc ),
+ maNoteData( rNote.maNoteData )
+{
+ maNoteData.mpCaption = 0;
+ CreateCaption( rPos, rNote.maNoteData.mpCaption );
+}
+
+ScPostIt::ScPostIt( ScDocument& rDoc, const ScNoteData& rNoteData ) :
+ mrDoc( rDoc ),
+ maNoteData( rNoteData )
+{
+}
+
+ScPostIt::~ScPostIt()
+{
+ RemoveCaption();
+}
+
+void ScPostIt::AutoStamp()
+{
+ maNoteData.maDate = ScGlobal::pLocaleData->getDate( Date() );
+ maNoteData.maAuthor = SvtUserOptions().GetID();
+}
+
+const EditTextObject* ScPostIt::GetEditTextObject() const
+{
+ if( maNoteData.mpCaption )
+ if( const OutlinerParaObject* pOPO = maNoteData.mpCaption->GetOutlinerParaObject() )
+ return &pOPO->GetTextObject();
+ return 0;
+}
+
+String ScPostIt::GetText() const
+{
+ String aText;
+ if( const EditTextObject* pEditObj = GetEditTextObject() )
+ {
+ for( USHORT nPara = 0, nParaCount = pEditObj->GetParagraphCount(); nPara < nParaCount; ++nPara )
+ {
+ if( nPara > 0 )
+ aText.Append( '\n' );
+ aText.Append( pEditObj->GetText( nPara ) );
+ }
+ }
+ return aText;
+}
+
+bool ScPostIt::HasMultiLineText() const
+{
+ const EditTextObject* pEditObj = GetEditTextObject();
+ return pEditObj && (pEditObj->GetParagraphCount() > 1);
+}
+
+void ScPostIt::SetText( const String& rText )
+{
+ if( maNoteData.mpCaption )
+ maNoteData.mpCaption->SetText( rText );
+}
+
+void ScPostIt::ShowCaption( bool bShow )
+{
+ maNoteData.mbShown = bShow;
+ UpdateCaptionLayer( maNoteData.mbShown );
+}
+
+void ScPostIt::ShowCaptionTemp( bool bShow )
+{
+ UpdateCaptionLayer( maNoteData.mbShown || bShow );
+}
+
+void ScPostIt::UpdateCaptionPos( const ScAddress& rPos )
+{
+ if( maNoteData.mpCaption )
+ {
+ ScCaptionCreator aCreator( mrDoc, rPos, *maNoteData.mpCaption );
+ aCreator.UpdateCaptionPos();
+ }
+}
+
+void ScPostIt::SetCaptionDefaultItems()
+{
+ if( maNoteData.mpCaption )
+ {
+ ScCaptionCreator aCreator( mrDoc, ScAddress(), *maNoteData.mpCaption );
+ aCreator.SetDefaultItems();
+ }
+}
+
+void ScPostIt::SetCaptionItems( const SfxItemSet& rItemSet )
+{
+ if( maNoteData.mpCaption )
+ {
+ ScCaptionCreator aCreator( mrDoc, ScAddress(), *maNoteData.mpCaption );
+ aCreator.SetCaptionItems( rItemSet );
+ }
+}
+
+// private --------------------------------------------------------------------
+
+void ScPostIt::CreateCaption( const ScAddress& rPos, const SdrCaptionObj* pCaption )
+{
+ DBG_ASSERT( !maNoteData.mpCaption, "ScPostIt::CreateCaption - unexpected caption object found" );
+ maNoteData.mpCaption = 0;
+
+ // drawing layer may be missing, if a note is copied into a clipboard document
+ DBG_ASSERT( !mrDoc.IsUndo(), "ScPostIt::CreateCaption - note caption should not be created in undo documents" );
+ if( mrDoc.IsClipboard() )
+ mrDoc.InitDrawLayer();
+
+ if( ScDrawLayer* pDrawLayer = mrDoc.GetDrawLayer() )
+ {
+ SdrPage* pDrawPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( rPos.Tab() ) );
+ DBG_ASSERT( pDrawPage, "ScPostIt::CreateCaption - no drawing page" );
+ if( pDrawPage )
+ {
+ // create the caption drawing object
+ ScCaptionCreator aCreator( mrDoc, rPos, maNoteData.mbShown, false );
+ maNoteData.mpCaption = aCreator.GetCaption();
+
+ // additional user data (pass true to create the object data entry)
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( maNoteData.mpCaption, true );
+ pData->maStart = rPos;
+ pData->mbNote = true;
+
+ // insert object into draw page
+ pDrawPage->InsertObject( maNoteData.mpCaption );
+
+ // clone settings of passed caption
+ if( pCaption )
+ {
+ // copy edit text object (object must be inserted into page already)
+ if( OutlinerParaObject* pOPO = pCaption->GetOutlinerParaObject() )
+ maNoteData.mpCaption->SetOutlinerParaObject( new OutlinerParaObject( *pOPO ) );
+ // copy formatting items (after text has been copied to apply font formatting)
+ maNoteData.mpCaption->SetMergedItemSetAndBroadcast( pCaption->GetMergedItemSet() );
+ // move textbox position relative to new cell, copy textbox size
+ Rectangle aCaptRect = pCaption->GetLogicRect();
+ Point aDist = maNoteData.mpCaption->GetTailPos() - pCaption->GetTailPos();
+ aCaptRect.Move( aDist.X(), aDist.Y() );
+ maNoteData.mpCaption->SetLogicRect( aCaptRect );
+ aCreator.FitCaptionToRect();
+ }
+ else
+ {
+ // set default formatting and default position
+ aCreator.SetDefaultItems();
+ aCreator.AutoPlaceCaption();
+ }
+
+ // create undo action
+ if( pDrawLayer->IsRecording() )
+ pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoNewObject( *maNoteData.mpCaption ) );
+ }
+ }
+}
+
+void ScPostIt::RemoveCaption()
+{
+ /* Remove caption object only, if this note is its owner (e.g. notes in
+ undo documents refer to captions in original document, do not remove
+ them from drawing layer here). */
+ if( maNoteData.mpCaption && (mrDoc.GetDrawLayer() == maNoteData.mpCaption->GetModel()) )
+ {
+ SdrPage* pDrawPage = maNoteData.mpCaption->GetPage();
+ DBG_ASSERT( pDrawPage, "ScPostIt::RemoveCaption - object without drawing page" );
+ if( pDrawPage )
+ {
+ pDrawPage->RecalcObjOrdNums();
+
+ ScDrawLayer* pDrawLayer = static_cast< ScDrawLayer* >( maNoteData.mpCaption->GetModel() );
+ DBG_ASSERT( pDrawLayer, "ScPostIt::RemoveCaption - object without drawing layer" );
+
+ // create drawing undo action (before removing the object to have valid draw page in undo action)
+ if( pDrawLayer && pDrawLayer->IsRecording() )
+ pDrawLayer->AddCalcUndo( pDrawLayer->GetSdrUndoFactory().CreateUndoDeleteObject( *maNoteData.mpCaption ) );
+
+ // remove the object from the drawing page, delete if undo is disabled
+ pDrawPage->RemoveObject( maNoteData.mpCaption->GetOrdNum() );
+ }
+ }
+ maNoteData.mpCaption = 0;
+}
+
+void ScPostIt::UpdateCaptionLayer( bool bShow )
+{
+ // no separate drawing undo needed, handled completely inside ScUndoShowHideNote
+ SdrLayerID nLayer = bShow ? SC_LAYER_INTERN : SC_LAYER_HIDDEN;
+ if( maNoteData.mpCaption && (nLayer != maNoteData.mpCaption->GetLayer()) )
+ maNoteData.mpCaption->SetLayer( nLayer );
+}
+
+// ============================================================================
+
+ScPostIt* ScNoteUtil::CloneNote( ScDocument& rDoc, const ScAddress& rPos, const ScPostIt& rNote, bool bCloneCaption )
+{
+ return bCloneCaption ? new ScPostIt( rDoc, rPos, rNote ) : new ScPostIt( rDoc, rNote.GetNoteData() );
+}
+
+void ScNoteUtil::UpdateCaptionPositions( ScDocument& rDoc, const ScRange& rRange )
+{
+ // do not use ScCellIterator, it skips filtered and subtotal cells
+ for( ScAddress aPos( rRange.aStart ); aPos.Tab() <= rRange.aEnd.Tab(); aPos.IncTab() )
+ for( aPos.SetCol( rRange.aStart.Col() ); aPos.Col() <= rRange.aEnd.Col(); aPos.IncCol() )
+ for( aPos.SetRow( rRange.aStart.Row() ); aPos.Row() <= rRange.aEnd.Row(); aPos.IncRow() )
+ if( ScPostIt* pNote = rDoc.GetNote( aPos ) )
+ pNote->UpdateCaptionPos( aPos );
+}
+
+SdrCaptionObj* ScNoteUtil::CreateTempCaption( ScDocument& rDoc, const ScAddress& rPos,
+ SdrPage& rPage, const String& rUserText, const Rectangle& rVisRect, bool bTailFront )
+{
+ String aFinalText = rUserText;
+ // add plain text of invisible (!) cell note (no formatting etc.)
+ SdrCaptionObj* pNoteCaption = 0;
+ if( ScPostIt* pNote = rDoc.GetNote( rPos ) )
+ {
+ if( !pNote->IsCaptionShown() )
+ {
+ if( aFinalText.Len() > 0 )
+ aFinalText.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "\n--------\n" ) );
+ aFinalText.Append( pNote->GetText() );
+ pNoteCaption = pNote->GetCaption();
+ }
+ }
+
+ // create a caption if any text exists
+ if( aFinalText.Len() == 0 )
+ return 0;
+
+ // prepare visible rectangle (add default distance to all borders)
+ Rectangle aVisRect(
+ rVisRect.Left() + SC_NOTECAPTION_BORDERDIST_TEMP,
+ rVisRect.Top() + SC_NOTECAPTION_BORDERDIST_TEMP,
+ rVisRect.Right() - SC_NOTECAPTION_BORDERDIST_TEMP,
+ rVisRect.Bottom() - SC_NOTECAPTION_BORDERDIST_TEMP );
+
+ // create the caption object
+ ScCaptionCreator aCreator( rDoc, rPos, true, bTailFront );
+ SdrCaptionObj* pCaption = aCreator.GetCaption();
+ // insert caption into page (needed to set caption text)
+ rPage.InsertObject( pCaption );
+ // set the text to the object
+ pCaption->SetText( aFinalText );
+
+ // set formatting (must be done after setting text) and resize the box to fit the text
+ if( pNoteCaption && (rUserText.Len() == 0) )
+ {
+ pCaption->SetMergedItemSetAndBroadcast( pNoteCaption->GetMergedItemSet() );
+ Rectangle aCaptRect( pCaption->GetLogicRect().TopLeft(), pNoteCaption->GetLogicRect().GetSize() );
+ pCaption->SetLogicRect( aCaptRect );
+ }
+ else
+ {
+ aCreator.SetDefaultItems();
+ // adjust caption size to text size
+ long nMaxWidth = ::std::min< long >( aVisRect.GetWidth() * 2 / 3, SC_NOTECAPTION_MAXWIDTH_TEMP );
+ pCaption->SetMergedItem( SdrTextAutoGrowWidthItem( TRUE ) );
+ pCaption->SetMergedItem( SdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
+ pCaption->SetMergedItem( SdrTextMaxFrameWidthItem( nMaxWidth ) );
+ pCaption->SetMergedItem( SdrTextAutoGrowHeightItem( TRUE ) );
+ pCaption->AdjustTextFrameWidthAndHeight();
+ }
+
+ // move caption into visible area
+ aCreator.AutoPlaceCaption( &aVisRect );
+ return pCaption;
+}
+
+ScPostIt* ScNoteUtil::CreateNoteFromString( ScDocument& rDoc, const ScAddress& rPos, const String& rNoteText, bool bShown )
+{
+ if( rNoteText.Len() == 0 )
+ return 0;
+ ScPostIt* pNote = new ScPostIt( rDoc, rPos, bShown );
+ rDoc.TakeNote( rPos, pNote );
+ if( SdrCaptionObj* pCaption = pNote->GetCaption() )
+ {
+ pCaption->SetText( rNoteText );
+ pNote->SetCaptionDefaultItems(); // reformat text with default font
+ pCaption->SetMergedItem( SdrTextMinFrameWidthItem( SC_NOTECAPTION_WIDTH ) );
+ pCaption->SetMergedItem( SdrTextMaxFrameWidthItem( SC_NOTECAPTION_MAXWIDTH_TEMP ) );
+ pCaption->AdjustTextFrameWidthAndHeight();
+ }
+ return pNote;
+}
+
+// ============================================================================
diff --git a/sc/source/core/data/scimpexpmsg.cxx b/sc/source/core/data/scimpexpmsg.cxx
new file mode 100644
index 000000000000..00dde7d9fa2a
--- /dev/null
+++ b/sc/source/core/data/scimpexpmsg.cxx
@@ -0,0 +1,116 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: scimpexpmsg.cxx,v $
+ * $Revision: 1.5.32.3 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "document.hxx"
+#include "scimpexpmsg.hxx"
+
+#include <tools/string.hxx>
+
+//UNUSED2008-05 ScImpExpLogMsg::ScImpExpLogMsg( ScImpExpMsg e ) : eId( e ), pPos( NULL ), pHint( NULL )
+//UNUSED2008-05 {
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05
+//UNUSED2008-05 ScImpExpLogMsg::ScImpExpLogMsg( ScImpExpMsg e, const String& r ) : eId( e ), pHint( NULL )
+//UNUSED2008-05 {
+//UNUSED2008-05 pPos = new String( r );
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05
+//UNUSED2008-05 ScImpExpLogMsg::ScImpExpLogMsg( ScImpExpMsg e, const String& rP, const String& rH ) : eId( e )
+//UNUSED2008-05 {
+//UNUSED2008-05 pPos = new String( rP );
+//UNUSED2008-05 pHint = new String( rH );
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05 ScImpExpLogMsg::ScImpExpLogMsg( const ScImpExpLogMsg& r ) : eId( r.eId )
+//UNUSED2008-05 {
+//UNUSED2008-05 if( r.pPos )
+//UNUSED2008-05 pPos = new String( *r.pPos );
+//UNUSED2008-05 else
+//UNUSED2008-05 pPos = NULL;
+//UNUSED2008-05
+//UNUSED2008-05 if( r.pHint )
+//UNUSED2008-05 pHint = new String( *r.pHint );
+//UNUSED2008-05 else
+//UNUSED2008-05 pHint = NULL;
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05
+//UNUSED2008-05 ScImpExpLogMsg::~ScImpExpLogMsg()
+//UNUSED2008-05 {
+//UNUSED2008-05 if( pPos )
+//UNUSED2008-05 delete pPos;
+//UNUSED2008-05
+//UNUSED2008-05 if( pHint )
+//UNUSED2008-05 delete pHint;
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05
+//UNUSED2008-05 void ScImpExpLogMsg::Set( ScImpExpMsg e, const String* pP, const String* pH )
+//UNUSED2008-05 {
+//UNUSED2008-05 eId = e;
+//UNUSED2008-05 if( pPos )
+//UNUSED2008-05 delete pPos;
+//UNUSED2008-05
+//UNUSED2008-05 if( pHint )
+//UNUSED2008-05 delete pHint;
+//UNUSED2008-05
+//UNUSED2008-05 if( pP )
+//UNUSED2008-05 pPos = new String( *pP );
+//UNUSED2008-05 else
+//UNUSED2008-05 pPos = NULL;
+//UNUSED2008-05
+//UNUSED2008-05 if( pH )
+//UNUSED2008-05 pHint = new String( *pH );
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05
+//UNUSED2008-05 String ScImpExpLogMsg::GetMsg( ScImpExpMsg e )
+//UNUSED2008-05 {
+//UNUSED2008-05 const sal_Char* p;
+//UNUSED2008-05 switch( e )
+//UNUSED2008-05 {
+//UNUSED2008-05 case SC_IMPEXPMSG_UNKNOWN: p = "unknown log message"; break;
+//UNUSED2008-05 default: p = "Not specified type of log message";
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05 String aRet;
+//UNUSED2008-05 aRet.AssignAscii( p );
+//UNUSED2008-05 return aRet;
+//UNUSED2008-05 }
+
diff --git a/sc/source/core/data/sortparam.cxx b/sc/source/core/data/sortparam.cxx
new file mode 100644
index 000000000000..15691a642d7e
--- /dev/null
+++ b/sc/source/core/data/sortparam.cxx
@@ -0,0 +1,265 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: sortparam.cxx,v $
+ * $Revision: 1.8.146.1 $
+ *
+ * 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 "sortparam.hxx"
+#include "global.hxx"
+#include "address.hxx"
+#include <tools/debug.hxx>
+
+
+//------------------------------------------------------------------------
+
+ScSortParam::ScSortParam()
+{
+ Clear();
+}
+
+//------------------------------------------------------------------------
+
+ScSortParam::ScSortParam( const ScSortParam& r ) :
+ nCol1(r.nCol1),nRow1(r.nRow1),nCol2(r.nCol2),nRow2(r.nRow2),
+ bHasHeader(r.bHasHeader),bByRow(r.bByRow),bCaseSens(r.bCaseSens),
+ bUserDef(r.bUserDef),nUserIndex(r.nUserIndex),bIncludePattern(r.bIncludePattern),
+ bInplace(r.bInplace),
+ nDestTab(r.nDestTab),nDestCol(r.nDestCol),nDestRow(r.nDestRow),
+ aCollatorLocale( r.aCollatorLocale ), aCollatorAlgorithm( r.aCollatorAlgorithm )
+{
+ for (USHORT i=0; i<MAXSORT; i++)
+ {
+ bDoSort[i] = r.bDoSort[i];
+ nField[i] = r.nField[i];
+ bAscending[i] = r.bAscending[i];
+ }
+}
+
+//------------------------------------------------------------------------
+
+void ScSortParam::Clear()
+{
+ nCol1=nCol2=nDestCol = 0;
+ nRow1=nRow2=nDestRow = 0;
+ nCompatHeader = 2;
+ nDestTab = 0;
+ nUserIndex = 0;
+ bHasHeader=bCaseSens=bUserDef = FALSE;
+ bByRow=bIncludePattern=bInplace = TRUE;
+ aCollatorLocale = ::com::sun::star::lang::Locale();
+ aCollatorAlgorithm.Erase();
+
+ for (USHORT i=0; i<MAXSORT; i++)
+ {
+ bDoSort[i] = FALSE;
+ nField[i] = 0;
+ bAscending[i] = TRUE;
+ }
+}
+
+//------------------------------------------------------------------------
+
+ScSortParam& ScSortParam::operator=( const ScSortParam& r )
+{
+ nCol1 = r.nCol1;
+ nRow1 = r.nRow1;
+ nCol2 = r.nCol2;
+ nRow2 = r.nRow2;
+ bHasHeader = r.bHasHeader;
+ bCaseSens = r.bCaseSens;
+ bByRow = r.bByRow;
+ bUserDef = r.bUserDef;
+ nUserIndex = r.nUserIndex;
+ bIncludePattern = r.bIncludePattern;
+ bInplace = r.bInplace;
+ nDestTab = r.nDestTab;
+ nDestCol = r.nDestCol;
+ nDestRow = r.nDestRow;
+ aCollatorLocale = r.aCollatorLocale;
+ aCollatorAlgorithm = r.aCollatorAlgorithm;
+
+ for (USHORT i=0; i<MAXSORT; i++)
+ {
+ bDoSort[i] = r.bDoSort[i];
+ nField[i] = r.nField[i];
+ bAscending[i] = r.bAscending[i];
+ }
+
+ return *this;
+}
+
+//------------------------------------------------------------------------
+
+BOOL ScSortParam::operator==( const ScSortParam& rOther ) const
+{
+ BOOL bEqual = FALSE;
+ // Anzahl der Sorts gleich?
+ USHORT nLast = 0;
+ USHORT nOtherLast = 0;
+ while ( bDoSort[nLast++] && nLast < MAXSORT ) ;
+ while ( rOther.bDoSort[nOtherLast++] && nOtherLast < MAXSORT ) ;
+ nLast--;
+ nOtherLast--;
+ if ( (nLast == nOtherLast)
+ && (nCol1 == rOther.nCol1)
+ && (nRow1 == rOther.nRow1)
+ && (nCol2 == rOther.nCol2)
+ && (nRow2 == rOther.nRow2)
+ && (bHasHeader == rOther.bHasHeader)
+ && (bByRow == rOther.bByRow)
+ && (bCaseSens == rOther.bCaseSens)
+ && (bUserDef == rOther.bUserDef)
+ && (nUserIndex == rOther.nUserIndex)
+ && (bIncludePattern == rOther.bIncludePattern)
+ && (bInplace == rOther.bInplace)
+ && (nDestTab == rOther.nDestTab)
+ && (nDestCol == rOther.nDestCol)
+ && (nDestRow == rOther.nDestRow)
+ && (aCollatorLocale.Language == rOther.aCollatorLocale.Language)
+ && (aCollatorLocale.Country == rOther.aCollatorLocale.Country)
+ && (aCollatorLocale.Variant == rOther.aCollatorLocale.Variant)
+ && (aCollatorAlgorithm == rOther.aCollatorAlgorithm)
+ )
+ {
+ bEqual = TRUE;
+ for ( USHORT i=0; i<=nLast && bEqual; i++ )
+ {
+ bEqual = (nField[i] == rOther.nField[i]) && (bAscending[i] == rOther.bAscending[i]);
+ }
+ }
+ return bEqual;
+}
+
+//------------------------------------------------------------------------
+
+ScSortParam::ScSortParam( const ScSubTotalParam& rSub, const ScSortParam& rOld ) :
+ nCol1(rSub.nCol1),nRow1(rSub.nRow1),nCol2(rSub.nCol2),nRow2(rSub.nRow2),
+ bHasHeader(TRUE),bByRow(TRUE),bCaseSens(rSub.bCaseSens),
+ bUserDef(rSub.bUserDef),nUserIndex(rSub.nUserIndex),bIncludePattern(rSub.bIncludePattern),
+ bInplace(TRUE),
+ nDestTab(0),nDestCol(0),nDestRow(0),
+ aCollatorLocale( rOld.aCollatorLocale ), aCollatorAlgorithm( rOld.aCollatorAlgorithm )
+{
+ USHORT nNewCount = 0;
+ USHORT i;
+
+ // zuerst die Gruppen aus den Teilergebnissen
+ if (rSub.bDoSort)
+ for (i=0; i<MAXSUBTOTAL; i++)
+ if (rSub.bGroupActive[i])
+ {
+ if (nNewCount < MAXSORT)
+ {
+ bDoSort[nNewCount] = TRUE;
+ nField[nNewCount] = rSub.nField[i];
+ bAscending[nNewCount] = rSub.bAscending;
+ ++nNewCount;
+ }
+ }
+
+ // dann dahinter die alten Einstellungen
+ for (i=0; i<MAXSORT; i++)
+ if (rOld.bDoSort[i])
+ {
+ SCCOLROW nThisField = rOld.nField[i];
+ BOOL bDouble = FALSE;
+ for (USHORT j=0; j<nNewCount; j++)
+ if ( nField[j] == nThisField )
+ bDouble = TRUE;
+ if (!bDouble) // ein Feld nicht zweimal eintragen
+ {
+ if (nNewCount < MAXSORT)
+ {
+ bDoSort[nNewCount] = TRUE;
+ nField[nNewCount] = nThisField;
+ bAscending[nNewCount] = rOld.bAscending[i];
+ ++nNewCount;
+ }
+ }
+ }
+
+ for (i=nNewCount; i<MAXSORT; i++) // Rest loeschen
+ {
+ bDoSort[i] = FALSE;
+ nField[i] = 0;
+ bAscending[i] = TRUE;
+ }
+}
+
+//------------------------------------------------------------------------
+
+ScSortParam::ScSortParam( const ScQueryParam& rParam, SCCOL nCol ) :
+ nCol1(nCol),nRow1(rParam.nRow1),nCol2(nCol),nRow2(rParam.nRow2),
+ bHasHeader(rParam.bHasHeader),bByRow(TRUE),bCaseSens(rParam.bCaseSens),
+//! TODO: what about Locale and Algorithm?
+ bUserDef(FALSE),nUserIndex(0),bIncludePattern(FALSE),
+ bInplace(TRUE),
+ nDestTab(0),nDestCol(0),nDestRow(0)
+{
+ bDoSort[0] = TRUE;
+ nField[0] = nCol;
+ bAscending[0] = TRUE;
+ for (USHORT i=1; i<MAXSORT; i++)
+ {
+ bDoSort[i] = FALSE;
+ nField[i] = 0;
+ bAscending[i] = TRUE;
+ }
+}
+
+//------------------------------------------------------------------------
+
+void ScSortParam::MoveToDest()
+{
+ if (!bInplace)
+ {
+ SCsCOL nDifX = ((SCsCOL) nDestCol) - ((SCsCOL) nCol1);
+ SCsROW nDifY = ((SCsROW) nDestRow) - ((SCsROW) nRow1);
+
+ nCol1 = sal::static_int_cast<SCCOL>( nCol1 + nDifX );
+ nRow1 = sal::static_int_cast<SCROW>( nRow1 + nDifY );
+ nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nDifX );
+ nRow2 = sal::static_int_cast<SCROW>( nRow2 + nDifY );
+ for (USHORT i=0; i<MAXSORT; i++)
+ if (bByRow)
+ nField[i] += nDifX;
+ else
+ nField[i] += nDifY;
+
+ bInplace = TRUE;
+ }
+ else
+ {
+ DBG_ERROR("MoveToDest, bInplace == TRUE");
+ }
+}
+
diff --git a/sc/source/core/data/stlpool.cxx b/sc/source/core/data/stlpool.cxx
new file mode 100644
index 000000000000..22926f31d003
--- /dev/null
+++ b/sc/source/core/data/stlpool.cxx
@@ -0,0 +1,643 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: stlpool.cxx,v $
+ * $Revision: 1.18.32.1 $
+ *
+ * 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/eeitem.hxx>
+#include <svx/algitem.hxx>
+#include <svx/boxitem.hxx>
+#include <svx/brshitem.hxx>
+#include <svx/editdata.hxx>
+#include <svx/editeng.hxx>
+#include <svx/editobj.hxx>
+#include <svx/fhgtitem.hxx>
+#include <svx/flditem.hxx>
+#include <svx/fontitem.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/postitem.hxx>
+#include <svx/udlnitem.hxx>
+#include <svx/wghtitem.hxx>
+#include <svtools/itemset.hxx>
+#include <svtools/zforlist.hxx>
+#include <unotools/charclass.hxx>
+#include <vcl/fontcvt.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/svapp.hxx>
+
+#include "sc.hrc"
+#include "attrib.hxx"
+#include "global.hxx"
+#include "globstr.hrc"
+#include "document.hxx"
+#include "docpool.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "rechead.hxx"
+#include "editutil.hxx"
+#include "patattr.hxx"
+
+
+//========================================================================
+
+ScStyleSheetPool::ScStyleSheetPool( SfxItemPool& rPoolP,
+ ScDocument* pDocument )
+ : SfxStyleSheetPool( rPoolP ),
+ pActualStyleSheet( NULL ),
+ pDoc( pDocument ),
+ pForceStdName( NULL )
+{
+}
+
+//------------------------------------------------------------------------
+
+__EXPORT ScStyleSheetPool::~ScStyleSheetPool()
+{
+}
+
+//------------------------------------------------------------------------
+
+void ScStyleSheetPool::SetDocument( ScDocument* pDocument )
+{
+ pDoc = pDocument;
+}
+
+//------------------------------------------------------------------------
+
+void ScStyleSheetPool::SetForceStdName( const String* pSet )
+{
+ pForceStdName = pSet;
+}
+
+//------------------------------------------------------------------------
+
+SfxStyleSheetBase& ScStyleSheetPool::Make( const String& rName,
+ SfxStyleFamily eFam, USHORT mask, USHORT nPos )
+{
+ // When updating styles from a template, Office 5.1 sometimes created
+ // files with multiple default styles.
+ // Create new styles in that case:
+
+ //! only when loading?
+
+ if ( rName.EqualsAscii(STRING_STANDARD) && Find( rName, eFam ) != NULL )
+ {
+ DBG_ERROR("renaming additional default style");
+ sal_uInt32 nCount = aStyles.size();
+ for ( sal_uInt32 nAdd = 1; nAdd <= nCount; nAdd++ )
+ {
+ String aNewName = ScGlobal::GetRscString(STR_STYLENAME_STANDARD);
+ aNewName += String::CreateFromInt32( nAdd );
+ if ( Find( aNewName, eFam ) == NULL )
+ return SfxStyleSheetPool::Make( aNewName, eFam, mask, nPos );
+ }
+ }
+
+ return SfxStyleSheetPool::Make( rName, eFam, mask, nPos );
+}
+
+//------------------------------------------------------------------------
+
+SfxStyleSheetBase* __EXPORT ScStyleSheetPool::Create(
+ const String& rName,
+ SfxStyleFamily eFamily,
+ USHORT nMaskP )
+{
+ ScStyleSheet* pSheet = new ScStyleSheet( rName, *this, eFamily, nMaskP );
+ if ( eFamily == SFX_STYLE_FAMILY_PARA && ScGlobal::GetRscString(STR_STYLENAME_STANDARD) != rName )
+ pSheet->SetParent( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) );
+
+ return pSheet;
+}
+
+//------------------------------------------------------------------------
+
+SfxStyleSheetBase* __EXPORT ScStyleSheetPool::Create( const SfxStyleSheetBase& rStyle )
+{
+ DBG_ASSERT( rStyle.ISA(ScStyleSheet), "Invalid StyleSheet-class! :-/" );
+ return new ScStyleSheet( (const ScStyleSheet&) rStyle );
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScStyleSheetPool::Remove( SfxStyleSheetBase* pStyle )
+{
+ if ( pStyle )
+ {
+ DBG_ASSERT( IS_SET( SFXSTYLEBIT_USERDEF, pStyle->GetMask() ),
+ "SFXSTYLEBIT_USERDEF not set!" );
+
+ ((ScDocumentPool&)rPool).StyleDeleted((ScStyleSheet*)pStyle);
+ SfxStyleSheetPool::Remove(pStyle);
+ }
+}
+
+//------------------------------------------------------------------------
+
+void ScStyleSheetPool::CopyStyleFrom( ScStyleSheetPool* pSrcPool,
+ const String& rName, SfxStyleFamily eFamily )
+{
+ // this ist Dest-Pool
+
+ SfxStyleSheetBase* pStyleSheet = pSrcPool->Find( rName, eFamily );
+ if (pStyleSheet)
+ {
+ const SfxItemSet& rSourceSet = pStyleSheet->GetItemSet();
+ SfxStyleSheetBase* pDestSheet = Find( rName, eFamily );
+ if (!pDestSheet)
+ pDestSheet = &Make( rName, eFamily );
+ SfxItemSet& rDestSet = pDestSheet->GetItemSet();
+ rDestSet.PutExtended( rSourceSet, SFX_ITEM_DONTCARE, SFX_ITEM_DEFAULT );
+
+ const SfxPoolItem* pItem;
+ if ( eFamily == SFX_STYLE_FAMILY_PAGE )
+ {
+ // Set-Items
+
+ if ( rSourceSet.GetItemState( ATTR_PAGE_HEADERSET, FALSE, &pItem ) == SFX_ITEM_SET )
+ {
+ const SfxItemSet& rSrcSub = ((const SvxSetItem*) pItem)->GetItemSet();
+ SfxItemSet aDestSub( *rDestSet.GetPool(), rSrcSub.GetRanges() );
+ aDestSub.PutExtended( rSrcSub, SFX_ITEM_DONTCARE, SFX_ITEM_DEFAULT );
+ rDestSet.Put( SvxSetItem( ATTR_PAGE_HEADERSET, aDestSub ) );
+ }
+ if ( rSourceSet.GetItemState( ATTR_PAGE_FOOTERSET, FALSE, &pItem ) == SFX_ITEM_SET )
+ {
+ const SfxItemSet& rSrcSub = ((const SvxSetItem*) pItem)->GetItemSet();
+ SfxItemSet aDestSub( *rDestSet.GetPool(), rSrcSub.GetRanges() );
+ aDestSub.PutExtended( rSrcSub, SFX_ITEM_DONTCARE, SFX_ITEM_DEFAULT );
+ rDestSet.Put( SvxSetItem( ATTR_PAGE_FOOTERSET, aDestSub ) );
+ }
+ }
+ else // cell styles
+ {
+ // #b5017505# number format exchange list has to be handled here, too
+
+ if ( pDoc && pDoc->GetFormatExchangeList() &&
+ rSourceSet.GetItemState( ATTR_VALUE_FORMAT, FALSE, &pItem ) == SFX_ITEM_SET )
+ {
+ ULONG nOldFormat = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
+ sal_uInt32* pNewFormat = static_cast<sal_uInt32*>(pDoc->GetFormatExchangeList()->Get( nOldFormat ));
+ if (pNewFormat)
+ rDestSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, *pNewFormat ) );
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+//
+// Standard-Vorlagen
+//
+//------------------------------------------------------------------------
+
+#define SCSTR(id) ScGlobal::GetRscString(id)
+
+void ScStyleSheetPool::CopyStdStylesFrom( ScStyleSheetPool* pSrcPool )
+{
+ // Default-Styles kopieren
+
+ CopyStyleFrom( pSrcPool, SCSTR(STR_STYLENAME_STANDARD), SFX_STYLE_FAMILY_PARA );
+ CopyStyleFrom( pSrcPool, SCSTR(STR_STYLENAME_RESULT), SFX_STYLE_FAMILY_PARA );
+ CopyStyleFrom( pSrcPool, SCSTR(STR_STYLENAME_RESULT1), SFX_STYLE_FAMILY_PARA );
+ CopyStyleFrom( pSrcPool, SCSTR(STR_STYLENAME_HEADLINE), SFX_STYLE_FAMILY_PARA );
+ CopyStyleFrom( pSrcPool, SCSTR(STR_STYLENAME_HEADLINE1), SFX_STYLE_FAMILY_PARA );
+ CopyStyleFrom( pSrcPool, SCSTR(STR_STYLENAME_STANDARD), SFX_STYLE_FAMILY_PAGE );
+ CopyStyleFrom( pSrcPool, SCSTR(STR_STYLENAME_REPORT), SFX_STYLE_FAMILY_PAGE );
+}
+
+//------------------------------------------------------------------------
+
+void lcl_CheckFont( SfxItemSet& rSet, LanguageType eLang, USHORT nFontType, USHORT nItemId )
+{
+ if ( eLang != LANGUAGE_NONE && eLang != LANGUAGE_DONTKNOW && eLang != LANGUAGE_SYSTEM )
+ {
+ Font aDefFont = OutputDevice::GetDefaultFont( nFontType, eLang, DEFAULTFONT_FLAGS_ONLYONE );
+ SvxFontItem aNewItem( aDefFont.GetFamily(), aDefFont.GetName(), aDefFont.GetStyleName(),
+ aDefFont.GetPitch(), aDefFont.GetCharSet(), nItemId );
+ if ( aNewItem != rSet.Get( nItemId ) )
+ {
+ // put item into style's ItemSet only if different from (static) default
+ rSet.Put( aNewItem );
+ }
+ }
+}
+
+void ScStyleSheetPool::CreateStandardStyles()
+{
+ // neue Eintraege auch bei CopyStdStylesFrom eintragen
+
+ Color aColBlack ( COL_BLACK );
+ Color aColGrey ( COL_LIGHTGRAY );
+ String aStr;
+ xub_StrLen nStrLen;
+ String aHelpFile;//XXX JN welcher Text???
+ ULONG nNumFmt = 0L;
+ SfxItemSet* pSet = NULL;
+ SfxItemSet* pHFSet = NULL;
+ SvxSetItem* pHFSetItem = NULL;
+ ScEditEngineDefaulter* pEdEngine = new ScEditEngineDefaulter( EditEngine::CreatePool(), TRUE );
+ pEdEngine->SetUpdateMode( FALSE );
+ EditTextObject* pEmptyTxtObj = pEdEngine->CreateTextObject();
+ EditTextObject* pTxtObj = NULL;
+ ScPageHFItem* pHeaderItem = new ScPageHFItem( ATTR_PAGE_HEADERRIGHT );
+ ScPageHFItem* pFooterItem = new ScPageHFItem( ATTR_PAGE_FOOTERRIGHT );
+ ScStyleSheet* pSheet = NULL;
+ SvxBorderLine aBorderLine ( &aColBlack, DEF_LINE_WIDTH_2 );
+ SvxBoxItem aBoxItem ( ATTR_BORDER );
+ SvxBoxInfoItem aBoxInfoItem ( ATTR_BORDER_INNER );
+
+ String aStrStandard = ScGlobal::GetRscString(STR_STYLENAME_STANDARD);
+
+ //==========================================================
+ // Zellformatvorlagen:
+ //==========================================================
+
+ //------------
+ // 1. Standard
+ //------------
+ pSheet = (ScStyleSheet*) &Make( aStrStandard, SFX_STYLE_FAMILY_PARA, SCSTYLEBIT_STANDARD );
+ pSheet->SetHelpId( aHelpFile, HID_SC_SHEET_CELL_STD );
+
+ // if default fonts for the document's languages are different from the pool default,
+ // put them into the default style
+ // (not as pool defaults, because pool defaults can't be changed by the user)
+ // the document languages must be set before creating the default styles!
+
+ pSet = &pSheet->GetItemSet();
+ LanguageType eLatin, eCjk, eCtl;
+ pDoc->GetLanguage( eLatin, eCjk, eCtl );
+
+ // #108374# / #107782#: If the UI language is Korean, the default Latin font has to
+ // be queried for Korean, too (the Latin language from the document can't be Korean).
+ // This is the same logic as in SwDocShell::InitNew.
+ LanguageType eUiLanguage = Application::GetSettings().GetUILanguage();
+ switch( eUiLanguage )
+ {
+ case LANGUAGE_KOREAN:
+ case LANGUAGE_KOREAN_JOHAB:
+ eLatin = eUiLanguage;
+ break;
+ }
+
+ lcl_CheckFont( *pSet, eLatin, DEFAULTFONT_LATIN_SPREADSHEET, ATTR_FONT );
+ lcl_CheckFont( *pSet, eCjk, DEFAULTFONT_CJK_SPREADSHEET, ATTR_CJK_FONT );
+ lcl_CheckFont( *pSet, eCtl, DEFAULTFONT_CTL_SPREADSHEET, ATTR_CTL_FONT );
+
+ // #i55300# default CTL font size for Thai has to be larger
+ // #i59408# The 15 point size causes problems with row heights, so no different
+ // size is used for Thai in Calc for now.
+// if ( eCtl == LANGUAGE_THAI )
+// pSet->Put( SvxFontHeightItem( 300, 100, ATTR_CTL_FONT_HEIGHT ) ); // 15 pt
+
+ //------------
+ // 2. Ergebnis
+ //------------
+
+ pSheet = (ScStyleSheet*) &Make( SCSTR( STR_STYLENAME_RESULT ),
+ SFX_STYLE_FAMILY_PARA,
+ SCSTYLEBIT_STANDARD );
+ pSheet->SetParent( aStrStandard );
+ pSheet->SetHelpId( aHelpFile, HID_SC_SHEET_CELL_ERG );
+ pSet = &pSheet->GetItemSet();
+ pSet->Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
+ pSet->Put( SvxPostureItem( ITALIC_NORMAL, ATTR_FONT_POSTURE ) );
+ pSet->Put( SvxUnderlineItem( UNDERLINE_SINGLE, ATTR_FONT_UNDERLINE ) );
+
+ //-------------
+ // 3. Ergebnis1
+ //-------------
+
+ pSheet = (ScStyleSheet*) &Make( SCSTR( STR_STYLENAME_RESULT1 ),
+ SFX_STYLE_FAMILY_PARA,
+ SCSTYLEBIT_STANDARD );
+
+ pSheet->SetParent( SCSTR( STR_STYLENAME_RESULT ) );
+ pSheet->SetHelpId( aHelpFile, HID_SC_SHEET_CELL_ERG1 );
+ pSet = &pSheet->GetItemSet();
+ nNumFmt = pDoc->GetFormatTable()->GetStandardFormat( NUMBERFORMAT_CURRENCY,
+ ScGlobal::eLnge );
+ pSet->Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumFmt ) );
+
+ //----------------
+ // 4. Ueberschrift
+ //----------------
+
+ pSheet = (ScStyleSheet*) &Make( SCSTR( STR_STYLENAME_HEADLINE ),
+ SFX_STYLE_FAMILY_PARA,
+ SCSTYLEBIT_STANDARD );
+
+ pSheet->SetParent( aStrStandard );
+ pSheet->SetHelpId( aHelpFile, HID_SC_SHEET_CELL_UEB );
+ pSet = &pSheet->GetItemSet();
+ pSet->Put( SvxFontHeightItem( 320, 100, ATTR_FONT_HEIGHT ) ); // 16pt
+ pSet->Put( SvxWeightItem( WEIGHT_BOLD, ATTR_FONT_WEIGHT ) );
+ pSet->Put( SvxPostureItem( ITALIC_NORMAL, ATTR_FONT_POSTURE ) );
+ pSet->Put( SvxHorJustifyItem( SVX_HOR_JUSTIFY_CENTER, ATTR_HOR_JUSTIFY ) );
+
+ //-----------------
+ // 5. Ueberschrift1
+ //-----------------
+
+ pSheet = (ScStyleSheet*) &Make( SCSTR( STR_STYLENAME_HEADLINE1 ),
+ SFX_STYLE_FAMILY_PARA,
+ SCSTYLEBIT_STANDARD );
+
+ pSheet->SetParent( SCSTR( STR_STYLENAME_HEADLINE ) );
+ pSheet->SetHelpId( aHelpFile, HID_SC_SHEET_CELL_UEB1 );
+ pSet = &pSheet->GetItemSet();
+ pSet->Put( SfxInt32Item( ATTR_ROTATE_VALUE, 9000 ) );
+
+ //==========================================================
+ // Seitenformat-Vorlagen:
+ //==========================================================
+
+ //------------
+ // 1. Standard
+ //------------
+
+ pSheet = (ScStyleSheet*) &Make( aStrStandard,
+ SFX_STYLE_FAMILY_PAGE,
+ SCSTYLEBIT_STANDARD );
+
+ pSet = &pSheet->GetItemSet();
+ pSheet->SetHelpId( aHelpFile, HID_SC_SHEET_PAGE_STD );
+
+ // Abstand der Kopf-/Fusszeilen von der Tabelle
+ pHFSetItem = new SvxSetItem( ((SvxSetItem&)pSet->Get( ATTR_PAGE_HEADERSET ) ) );
+ pSet->Put( *pHFSetItem, ATTR_PAGE_HEADERSET );
+ pSet->Put( *pHFSetItem, ATTR_PAGE_FOOTERSET );
+ DELETEZ( pHFSetItem );
+
+ //----------------------------------------
+ // Kopfzeile:
+ // [leer][\TABELLE\][leer]
+ //----------------------------------------
+ pEdEngine->SetText(EMPTY_STRING);
+ pEdEngine->QuickInsertField( SvxFieldItem(SvxTableField(), EE_FEATURE_FIELD), ESelection() );
+ pTxtObj = pEdEngine->CreateTextObject();
+ pHeaderItem->SetLeftArea ( *pEmptyTxtObj );
+ pHeaderItem->SetCenterArea( *pTxtObj );
+ pHeaderItem->SetRightArea ( *pEmptyTxtObj );
+ pSet->Put( *pHeaderItem );
+ DELETEZ( pTxtObj );
+
+ //----------------------------------------
+ // Fusszeile:
+ // [leer][Seite \SEITE\][leer]
+ //----------------------------------------
+ aStr = SCSTR( STR_PAGE ); aStr += ' ';
+ pEdEngine->SetText( aStr );
+ nStrLen = aStr.Len();
+ pEdEngine->QuickInsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD), ESelection(0,nStrLen,0,nStrLen) );
+ pTxtObj = pEdEngine->CreateTextObject();
+ pFooterItem->SetLeftArea ( *pEmptyTxtObj );
+ pFooterItem->SetCenterArea( *pTxtObj );
+ pFooterItem->SetRightArea ( *pEmptyTxtObj );
+ pSet->Put( *pFooterItem );
+ DELETEZ( pTxtObj );
+
+ //----------
+ // 2. Report
+ //----------
+
+ pSheet = (ScStyleSheet*) &Make( SCSTR( STR_STYLENAME_REPORT ),
+ SFX_STYLE_FAMILY_PAGE,
+ SCSTYLEBIT_STANDARD );
+ pSet = &pSheet->GetItemSet();
+ pSheet->SetHelpId( aHelpFile, HID_SC_SHEET_PAGE_REP );
+
+ // Hintergrund und Umrandung
+ aBoxItem.SetLine( &aBorderLine, BOX_LINE_TOP );
+ aBoxItem.SetLine( &aBorderLine, BOX_LINE_BOTTOM );
+ aBoxItem.SetLine( &aBorderLine, BOX_LINE_LEFT );
+ aBoxItem.SetLine( &aBorderLine, BOX_LINE_RIGHT );
+ aBoxItem.SetDistance( 10 ); // 0.2mm
+ aBoxInfoItem.SetValid( VALID_TOP, TRUE );
+ aBoxInfoItem.SetValid( VALID_BOTTOM, TRUE );
+ aBoxInfoItem.SetValid( VALID_LEFT, TRUE );
+ aBoxInfoItem.SetValid( VALID_RIGHT, TRUE );
+ aBoxInfoItem.SetValid( VALID_DISTANCE, TRUE );
+ aBoxInfoItem.SetTable( FALSE );
+ aBoxInfoItem.SetDist ( TRUE );
+
+ pHFSetItem = new SvxSetItem( ((SvxSetItem&)pSet->Get( ATTR_PAGE_HEADERSET ) ) );
+ pHFSet = &(pHFSetItem->GetItemSet());
+
+ pHFSet->Put( SvxBrushItem( aColGrey, ATTR_BACKGROUND ) );
+ pHFSet->Put( aBoxItem );
+ pHFSet->Put( aBoxInfoItem );
+ pSet->Put( *pHFSetItem, ATTR_PAGE_HEADERSET );
+ pSet->Put( *pHFSetItem, ATTR_PAGE_FOOTERSET );
+ DELETEZ( pHFSetItem );
+
+ //----------------------------------------
+ // Kopfzeile:
+ // [\TABELLE\ (\DATEI\)][leer][\DATUM\, \ZEIT\]
+ //----------------------------------------
+ aStr = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM(" ()"));
+ pEdEngine->SetText( aStr );
+ pEdEngine->QuickInsertField( SvxFieldItem(SvxFileField(), EE_FEATURE_FIELD), ESelection(0,2,0,2) );
+ pEdEngine->QuickInsertField( SvxFieldItem(SvxTableField(), EE_FEATURE_FIELD), ESelection() );
+ pTxtObj = pEdEngine->CreateTextObject();
+ pHeaderItem->SetLeftArea( *pTxtObj );
+ pHeaderItem->SetCenterArea( *pEmptyTxtObj );
+ DELETEZ( pTxtObj );
+ aStr = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM(", "));
+ pEdEngine->SetText( aStr );
+ pEdEngine->QuickInsertField( SvxFieldItem(SvxTimeField(), EE_FEATURE_FIELD), ESelection(0,2,0,2) );
+ pEdEngine->QuickInsertField( SvxFieldItem(SvxDateField(Date(),SVXDATETYPE_VAR), EE_FEATURE_FIELD),
+ ESelection() );
+ pTxtObj = pEdEngine->CreateTextObject();
+ pHeaderItem->SetRightArea( *pTxtObj );
+ DELETEZ( pTxtObj );
+ pSet->Put( *pHeaderItem );
+
+ //----------------------------------------
+ // Fusszeile:
+ // [leer][Seite: \SEITE\ / \SEITEN\][leer]
+ //----------------------------------------
+ aStr = SCSTR( STR_PAGE ); aStr += ' ';
+ nStrLen = aStr.Len();
+ aStr.AppendAscii(RTL_CONSTASCII_STRINGPARAM(" / "));
+ xub_StrLen nStrLen2 = aStr.Len();
+ pEdEngine->SetText( aStr );
+ pEdEngine->QuickInsertField( SvxFieldItem(SvxPagesField(), EE_FEATURE_FIELD), ESelection(0,nStrLen2,0,nStrLen2) );
+ pEdEngine->QuickInsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD), ESelection(0,nStrLen,0,nStrLen) );
+ pTxtObj = pEdEngine->CreateTextObject();
+ pFooterItem->SetLeftArea ( *pEmptyTxtObj );
+ pFooterItem->SetCenterArea( *pTxtObj );
+ pFooterItem->SetRightArea ( *pEmptyTxtObj );
+ pSet->Put( *pFooterItem );
+ DELETEZ( pTxtObj );
+
+ //----------------------------------------------------
+ DELETEZ( pEmptyTxtObj );
+ DELETEZ( pHeaderItem );
+ DELETEZ( pFooterItem );
+ DELETEZ( pEdEngine );
+}
+
+//------------------------------------------------------------------------
+
+//UNUSED2008-05 void ScStyleSheetPool::UpdateStdNames()
+//UNUSED2008-05 {
+//UNUSED2008-05 // Standard-Styles den richtigen Namen in der Programm-Sprache geben
+//UNUSED2008-05
+//UNUSED2008-05 String aHelpFile;
+//UNUSED2008-05 sal_uInt32 nCount = aStyles.size();
+//UNUSED2008-05 for (sal_uInt32 n=0; n<nCount; n++)
+//UNUSED2008-05 {
+//UNUSED2008-05 SfxStyleSheetBase* pStyle = aStyles[n].get();
+//UNUSED2008-05 if (!pStyle->IsUserDefined())
+//UNUSED2008-05 {
+//UNUSED2008-05 String aOldName = pStyle->GetName();
+//UNUSED2008-05 ULONG nHelpId = pStyle->GetHelpId( aHelpFile );
+//UNUSED2008-05 SfxStyleFamily eFam = pStyle->GetFamily();
+//UNUSED2008-05
+//UNUSED2008-05 BOOL bHelpKnown = TRUE;
+//UNUSED2008-05 String aNewName;
+//UNUSED2008-05 USHORT nNameId = 0;
+//UNUSED2008-05 switch( nHelpId )
+//UNUSED2008-05 {
+//UNUSED2008-05 case HID_SC_SHEET_CELL_STD:
+//UNUSED2008-05 case HID_SC_SHEET_PAGE_STD: nNameId = STR_STYLENAME_STANDARD; break;
+//UNUSED2008-05 case HID_SC_SHEET_CELL_ERG: nNameId = STR_STYLENAME_RESULT; break;
+//UNUSED2008-05 case HID_SC_SHEET_CELL_ERG1: nNameId = STR_STYLENAME_RESULT1; break;
+//UNUSED2008-05 case HID_SC_SHEET_CELL_UEB: nNameId = STR_STYLENAME_HEADLINE; break;
+//UNUSED2008-05 case HID_SC_SHEET_CELL_UEB1: nNameId = STR_STYLENAME_HEADLINE1; break;
+//UNUSED2008-05 case HID_SC_SHEET_PAGE_REP: nNameId = STR_STYLENAME_REPORT; break;
+//UNUSED2008-05 default:
+//UNUSED2008-05 // 0 oder falsche (alte) HelpId
+//UNUSED2008-05 bHelpKnown = FALSE;
+//UNUSED2008-05 }
+//UNUSED2008-05 if (bHelpKnown)
+//UNUSED2008-05 {
+//UNUSED2008-05 if ( nNameId )
+//UNUSED2008-05 aNewName = SCSTR( nNameId );
+//UNUSED2008-05
+//UNUSED2008-05 if ( aNewName.Len() && aNewName != aOldName && !Find( aNewName, eFam ) )
+//UNUSED2008-05 {
+//UNUSED2008-05 DBG_TRACE( "Renaming style..." );
+//UNUSED2008-05
+//UNUSED2008-05 pStyle->SetName( aNewName ); // setzt auch Parents um
+//UNUSED2008-05
+//UNUSED2008-05 // Styles in Patterns sind schon auf Pointer umgesetzt
+//UNUSED2008-05 if (eFam == SFX_STYLE_FAMILY_PAGE)
+//UNUSED2008-05 {
+//UNUSED2008-05 // Page-Styles umsetzen
+//UNUSED2008-05 // TableCount am Doc ist noch nicht initialisiert
+//UNUSED2008-05 for (SCTAB nTab=0; nTab<=MAXTAB && pDoc->HasTable(nTab); nTab++)
+//UNUSED2008-05 if (pDoc->GetPageStyle(nTab) == aOldName)
+//UNUSED2008-05 pDoc->SetPageStyle(nTab, aNewName);
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 else
+//UNUSED2008-05 {
+//UNUSED2008-05 // wrong or no HelpId -> set new HelpId
+//UNUSED2008-05
+//UNUSED2008-05 // no assertion for wrong HelpIds because this happens
+//UNUSED2008-05 // with old files (#67218#) or with old files that were
+//UNUSED2008-05 // saved again with a new version in a different language
+//UNUSED2008-05 // (so SrcVersion doesn't help)
+//UNUSED2008-05
+//UNUSED2008-05 USHORT nNewId = 0;
+//UNUSED2008-05 if ( eFam == SFX_STYLE_FAMILY_PARA )
+//UNUSED2008-05 {
+//UNUSED2008-05 if ( aOldName == SCSTR( STR_STYLENAME_STANDARD ) )
+//UNUSED2008-05 nNewId = HID_SC_SHEET_CELL_STD;
+//UNUSED2008-05 else if ( aOldName == SCSTR( STR_STYLENAME_RESULT ) )
+//UNUSED2008-05 nNewId = HID_SC_SHEET_CELL_ERG;
+//UNUSED2008-05 else if ( aOldName == SCSTR( STR_STYLENAME_RESULT1 ) )
+//UNUSED2008-05 nNewId = HID_SC_SHEET_CELL_ERG1;
+//UNUSED2008-05 else if ( aOldName == SCSTR( STR_STYLENAME_HEADLINE ) )
+//UNUSED2008-05 nNewId = HID_SC_SHEET_CELL_UEB;
+//UNUSED2008-05 else if ( aOldName == SCSTR( STR_STYLENAME_HEADLINE1 ) )
+//UNUSED2008-05 nNewId = HID_SC_SHEET_CELL_UEB1;
+//UNUSED2008-05 }
+//UNUSED2008-05 else // PAGE
+//UNUSED2008-05 {
+//UNUSED2008-05 if ( aOldName == SCSTR( STR_STYLENAME_STANDARD ) )
+//UNUSED2008-05 nNewId = HID_SC_SHEET_PAGE_STD;
+//UNUSED2008-05 else if ( aOldName == SCSTR( STR_STYLENAME_REPORT ) )
+//UNUSED2008-05 nNewId = HID_SC_SHEET_PAGE_REP;
+//UNUSED2008-05 }
+//UNUSED2008-05
+//UNUSED2008-05 if ( nNewId ) // new ID found from name -> set ID
+//UNUSED2008-05 {
+//UNUSED2008-05 pStyle->SetHelpId( aHelpFile, nNewId );
+//UNUSED2008-05 }
+//UNUSED2008-05 else if ( nHelpId == 0 ) // no old and no new ID
+//UNUSED2008-05 {
+//UNUSED2008-05 // #71471# probably user defined style without SFXSTYLEBIT_USERDEF set
+//UNUSED2008-05 // (from StarCalc 1.0 import), fixed in src563 and above
+//UNUSED2008-05 //! may also be default style from a different language
+//UNUSED2008-05 //! test if name was generated from StarCalc 1.0 import?
+//UNUSED2008-05 DBG_ASSERT(pDoc->GetSrcVersion() <= SC_SUBTOTAL_BUGFIX,
+//UNUSED2008-05 "user defined style without SFXSTYLEBIT_USERDEF");
+//UNUSED2008-05 pStyle->SetMask( pStyle->GetMask() | SFXSTYLEBIT_USERDEF );
+//UNUSED2008-05 }
+//UNUSED2008-05 // else: wrong old ID and no new ID found:
+//UNUSED2008-05 // probably default style from a different language
+//UNUSED2008-05 // -> leave unchanged (HelpId will be set if loaded with matching
+//UNUSED2008-05 // language version later)
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+//UNUSED2008-05 }
+
+//------------------------------------------------------------------------
+
+ScStyleSheet* ScStyleSheetPool::FindCaseIns( const String& rName, SfxStyleFamily eFam )
+{
+ String aUpSearch = rName;
+ ScGlobal::pCharClass->toUpper(aUpSearch);
+
+ sal_uInt32 nCount = aStyles.size();
+ for (sal_uInt32 n=0; n<nCount; n++)
+ {
+ SfxStyleSheetBase* pStyle = aStyles[n].get();
+ if ( pStyle->GetFamily() == eFam )
+ {
+ String aUpName = pStyle->GetName();
+ ScGlobal::pCharClass->toUpper(aUpName);
+ if (aUpName == aUpSearch)
+ return (ScStyleSheet*)pStyle;
+ }
+ }
+
+ return NULL;
+}
+
diff --git a/sc/source/core/data/stlsheet.cxx b/sc/source/core/data/stlsheet.cxx
new file mode 100644
index 000000000000..37dce231cbaf
--- /dev/null
+++ b/sc/source/core/data/stlsheet.cxx
@@ -0,0 +1,342 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: stlsheet.cxx,v $
+ * $Revision: 1.12 $
+ *
+ * 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 "document.hxx"
+#include "stlsheet.hxx"
+#include "stlpool.hxx"
+
+#include "scitems.hxx"
+#include <svx/boxitem.hxx>
+#include <svx/frmdiritem.hxx>
+#include <svx/lrspitem.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/paperinf.hxx>
+#include <svx/pbinitem.hxx>
+#include <svx/sizeitem.hxx>
+#include <svx/ulspitem.hxx>
+#include <sfx2/printer.hxx>
+#include <svtools/itempool.hxx>
+#include <svtools/itemset.hxx>
+#include <svtools/smplhint.hxx>
+#include "attrib.hxx"
+
+#include <vcl/svapp.hxx> // GetSettings()
+
+#include "globstr.hrc"
+
+//------------------------------------------------------------------------
+
+TYPEINIT1(ScStyleSheet, SfxStyleSheet);
+
+#define TWO_CM 1134
+#define HFDIST_CM 142
+
+//========================================================================
+
+ScStyleSheet::ScStyleSheet( const String& rName,
+ ScStyleSheetPool& rPoolP,
+ SfxStyleFamily eFamily,
+ USHORT nMaskP )
+
+ : SfxStyleSheet ( rName, rPoolP, eFamily, nMaskP )
+ , eUsage( UNKNOWN )
+{
+}
+
+//------------------------------------------------------------------------
+
+ScStyleSheet::ScStyleSheet( const ScStyleSheet& rStyle )
+ : SfxStyleSheet ( rStyle )
+ , eUsage( UNKNOWN )
+{
+}
+
+//------------------------------------------------------------------------
+
+__EXPORT ScStyleSheet::~ScStyleSheet()
+{
+}
+
+//------------------------------------------------------------------------
+
+BOOL __EXPORT ScStyleSheet::HasFollowSupport() const
+{
+ return FALSE;
+}
+
+//------------------------------------------------------------------------
+
+BOOL __EXPORT ScStyleSheet::HasParentSupport () const
+{
+ BOOL bHasParentSupport = FALSE;
+
+ switch ( GetFamily() )
+ {
+ case SFX_STYLE_FAMILY_PARA: bHasParentSupport = TRUE; break;
+ case SFX_STYLE_FAMILY_PAGE: bHasParentSupport = FALSE; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ return bHasParentSupport;
+}
+
+//------------------------------------------------------------------------
+
+BOOL __EXPORT ScStyleSheet::SetParent( const String& rParentName )
+{
+ BOOL bResult = FALSE;
+ String aEffName = rParentName;
+ SfxStyleSheetBase* pStyle = rPool.Find( aEffName, nFamily );
+ if (!pStyle)
+ {
+ SfxStyleSheetIterator* pIter = rPool.CreateIterator( nFamily, SFXSTYLEBIT_ALL );
+ pStyle = pIter->First();
+ if (pStyle)
+ aEffName = pStyle->GetName();
+ }
+
+ if ( pStyle && aEffName != GetName() )
+ {
+ bResult = SfxStyleSheet::SetParent( aEffName );
+ if (bResult)
+ {
+ SfxItemSet& rParentSet = pStyle->GetItemSet();
+ GetItemSet().SetParent( &rParentSet );
+ }
+ }
+
+ return bResult;
+}
+
+//------------------------------------------------------------------------
+
+SfxItemSet& __EXPORT ScStyleSheet::GetItemSet()
+{
+ if ( !pSet )
+ {
+ switch ( GetFamily() )
+ {
+ case SFX_STYLE_FAMILY_PAGE:
+ {
+ // Seitenvorlagen sollen nicht ableitbar sein,
+ // deshalb werden an dieser Stelle geeignete
+ // Werte eingestellt. (==Standard-Seitenvorlage)
+
+ SfxItemPool& rItemPool = GetPool().GetPool();
+ pSet = new SfxItemSet( rItemPool,
+ ATTR_BACKGROUND, ATTR_BACKGROUND,
+ ATTR_BORDER, ATTR_SHADOW,
+ ATTR_LRSPACE, ATTR_PAGE_SCALETO,
+ ATTR_WRITINGDIR, ATTR_WRITINGDIR,
+ ATTR_USERDEF, ATTR_USERDEF,
+ 0 );
+
+ // Wenn gerade geladen wird, wird auch der Set hinterher aus der Datei
+ // gefuellt, es brauchen also keine Defaults gesetzt zu werden.
+ // GetPrinter wuerde dann auch einen neuen Printer anlegen, weil der
+ // gespeicherte Printer noch nicht geladen ist!
+
+ ScDocument* pDoc = ((ScStyleSheetPool&)GetPool()).GetDocument();
+ if ( pDoc && pDoc->IsLoadingDone() )
+ {
+ // Setzen von sinnvollen Default-Werten:
+ // SfxPrinter* pPrinter = pDoc->GetPrinter();
+ SvxPageItem aPageItem( ATTR_PAGE );
+ // #50536# PaperBin auf Default lassen,
+ // nicht auf aktuelle Drucker-Einstellung umsetzen
+ // SvxSizeItem aPaperSizeItem(ATTR_PAGE_SIZE,SvxPaperInfo::GetPaperSize(pPrinter) );
+
+ SvxPaper aDefaultPaper = SvxPaperInfo::GetDefaultSvxPaper( Application::GetSettings().GetLanguage() );
+ SvxSizeItem aPaperSizeItem( ATTR_PAGE_SIZE, SvxPaperInfo::GetPaperSize(aDefaultPaper) );
+
+ SvxSetItem aHFSetItem(
+ (const SvxSetItem&)
+ rItemPool.GetDefaultItem(ATTR_PAGE_HEADERSET) );
+
+ SfxItemSet& rHFSet = aHFSetItem.GetItemSet();
+ SvxSizeItem aHFSizeItem( // 0,5 cm + Abstand
+ ATTR_PAGE_SIZE,
+ Size( 0, (long)( 500 / HMM_PER_TWIPS ) + HFDIST_CM ) );
+
+ SvxULSpaceItem aHFDistItem ( HFDIST_CM,// nUp
+ HFDIST_CM,// nLow
+ ATTR_ULSPACE );
+
+ SvxLRSpaceItem aLRSpaceItem( TWO_CM, // nLeft
+ TWO_CM, // nRight
+ TWO_CM, // nTLeft
+ 0, // nFirstLineOffset
+ ATTR_LRSPACE );
+ SvxULSpaceItem aULSpaceItem( TWO_CM, // nUp
+ TWO_CM, // nLow
+ ATTR_ULSPACE );
+ SvxBoxInfoItem aBoxInfoItem( ATTR_BORDER_INNER );
+
+ aBoxInfoItem.SetTable( FALSE );
+ aBoxInfoItem.SetDist( TRUE );
+ aBoxInfoItem.SetValid( VALID_DISTANCE, TRUE );
+
+ // aPageItem.SetLandscape( ORIENTATION_LANDSCAPE == pPrinter->GetOrientation() );
+ aPageItem.SetLandscape( FALSE );
+
+ rHFSet.Put( aBoxInfoItem );
+ rHFSet.Put( aHFSizeItem );
+ rHFSet.Put( aHFDistItem );
+ rHFSet.Put( SvxLRSpaceItem( 0,0,0,0, ATTR_LRSPACE ) ); // Rand auf Null setzen
+
+ pSet->Put( aHFSetItem, ATTR_PAGE_HEADERSET );
+ pSet->Put( aHFSetItem, ATTR_PAGE_FOOTERSET );
+ pSet->Put( aBoxInfoItem ); // PoolDefault wg. Formatvorlagen
+ // nicht ueberschreiben!
+
+ // Writing direction: not as pool default because the default for cells
+ // must remain FRMDIR_ENVIRONMENT, and each page style's setting is
+ // supposed to be saved in the file format.
+ // The page default depends on the system language.
+ SvxFrameDirection eDirection = ScGlobal::IsSystemRTL() ?
+ FRMDIR_HORI_RIGHT_TOP : FRMDIR_HORI_LEFT_TOP;
+ pSet->Put( SvxFrameDirectionItem( eDirection, ATTR_WRITINGDIR ), ATTR_WRITINGDIR );
+
+ rItemPool.SetPoolDefaultItem( aPageItem );
+ rItemPool.SetPoolDefaultItem( aPaperSizeItem );
+ rItemPool.SetPoolDefaultItem( aLRSpaceItem );
+ rItemPool.SetPoolDefaultItem( aULSpaceItem );
+ rItemPool.SetPoolDefaultItem( SfxUInt16Item( ATTR_PAGE_SCALE, 100 ) );
+ ScPageScaleToItem aScaleToItem;
+ rItemPool.SetPoolDefaultItem( aScaleToItem );
+ rItemPool.SetPoolDefaultItem( SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, 0 ) );
+ }
+ }
+ break;
+
+ case SFX_STYLE_FAMILY_PARA:
+ default:
+ pSet = new SfxItemSet( GetPool().GetPool(),
+ ATTR_PATTERN_START, ATTR_PATTERN_END,
+ 0 );
+ break;
+ }
+ bMySet = TRUE;
+ }
+
+ return *pSet;
+}
+
+//------------------------------------------------------------------------
+
+BOOL __EXPORT ScStyleSheet::IsUsed() const
+{
+ if ( GetFamily() == SFX_STYLE_FAMILY_PARA )
+ {
+ // Always query the document to let it decide if a rescan is necessary,
+ // and store the state.
+ ScDocument* pDoc = ((ScStyleSheetPool&)rPool).GetDocument();
+ if ( pDoc && pDoc->IsStyleSheetUsed( *this, TRUE ) )
+ eUsage = USED;
+ else
+ eUsage = NOTUSED;
+ return eUsage == USED;
+ }
+ else
+ return TRUE;
+}
+
+//------------------------------------------------------------------------
+
+void __EXPORT ScStyleSheet::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.ISA(SfxSimpleHint) )
+ if ( ((SfxSimpleHint&)rHint).GetId() == SFX_HINT_DYING )
+ GetItemSet().SetParent( NULL );
+}
+
+//------------------------------------------------------------------------
+
+// #66123# schmutzige Tricks, um die Standard-Vorlage immer als "Standard" zu speichern,
+// obwohl der fuer den Benutzer sichtbare Name uebersetzt ist:
+
+const String& ScStyleSheet::GetName() const
+{
+ const String& rBase = SfxStyleSheet::GetName();
+ const String* pForceStdName = ((ScStyleSheetPool&)rPool).GetForceStdName();
+ if ( pForceStdName && rBase == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
+ return *pForceStdName;
+ else
+ return rBase;
+}
+
+const String& ScStyleSheet::GetParent() const
+{
+ const String& rBase = SfxStyleSheet::GetParent();
+ const String* pForceStdName = ((ScStyleSheetPool&)rPool).GetForceStdName();
+ if ( pForceStdName && rBase == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
+ return *pForceStdName;
+ else
+ return rBase;
+}
+
+const String& ScStyleSheet::GetFollow() const
+{
+ const String& rBase = SfxStyleSheet::GetFollow();
+ const String* pForceStdName = ((ScStyleSheetPool&)rPool).GetForceStdName();
+ if ( pForceStdName && rBase == ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
+ return *pForceStdName;
+ else
+ return rBase;
+}
+
+// Verhindern, dass ein Style "Standard" angelegt wird, wenn das nicht der
+// Standard-Name ist, weil sonst beim Speichern zwei Styles denselben Namen haetten
+// (Beim Laden wird der Style direkt per Make mit dem Namen erzeugt, so dass diese
+// Abfrage dann nicht gilt)
+//! Wenn irgendwann aus dem Laden SetName aufgerufen wird, muss fuer das Laden ein
+//! Flag gesetzt und abgefragt werden.
+//! Die ganze Abfrage muss raus, wenn fuer eine neue Datei-Version die Namens-Umsetzung wegfaellt.
+
+BOOL ScStyleSheet::SetName( const String& rNew )
+{
+ String aFileStdName = String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM(STRING_STANDARD));
+ if ( rNew == aFileStdName && aFileStdName != ScGlobal::GetRscString(STR_STYLENAME_STANDARD) )
+ return FALSE;
+ else
+ return SfxStyleSheet::SetName( rNew );
+}
+
+
+
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
new file mode 100644
index 000000000000..03b9fc9d90be
--- /dev/null
+++ b/sc/source/core/data/table1.cxx
@@ -0,0 +1,1486 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: table1.cxx,v $
+ * $Revision: 1.25.30.2 $
+ *
+ * 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"
+
+
+
+//------------------------------------------------------------------------
+
+#ifdef WIN
+
+// SFX
+#define _SFXAPPWIN_HXX
+#define _SFX_SAVEOPT_HXX
+//#define _SFX_CHILDWIN_HXX ***
+#define _SFXCTRLITEM_HXX
+#define _SFXPRNMON_HXX
+#define _INTRO_HXX
+#define _SFXMSGDESCR_HXX
+#define _SFXMSGPOOL_HXX
+#define _SFXFILEDLG_HXX
+#define _PASSWD_HXX
+#define _SFXTBXCTRL_HXX
+#define _SFXSTBITEM_HXX
+#define _SFXMNUITEM_HXX
+#define _SFXIMGMGR_HXX
+#define _SFXTBXMGR_HXX
+#define _SFXSTBMGR_HXX
+#define _SFX_MINFITEM_HXX
+#define _SFXEVENT_HXX
+
+//#define _SI_HXX
+//#define SI_NODRW
+#define _SI_DLL_HXX
+#define _SIDLL_HXX
+#define _SI_NOITEMS
+#define _SI_NOOTHERFORMS
+#define _SI_NOSBXCONTROLS
+#define _SINOSBXCONTROLS
+#define _SI_NODRW //
+#define _SI_NOCONTROL
+#define _VCBRW_HXX
+#define _VCTRLS_HXX
+//#define _VCSBX_HXX
+#define _VCONT_HXX
+#define _VDRWOBJ_HXX
+#define _VCATTR_HXX
+
+
+#define _SVX_DAILDLL_HXX
+#define _SVX_HYPHEN_HXX
+#define _SVX_IMPGRF_HXX
+#define _SVX_OPTITEMS_HXX
+#define _SVX_OPTGERL_HXX
+#define _SVX_OPTSAVE_HXX
+#define _SVX_OPTSPELL_HXX
+#define _SVX_OPTPATH_HXX
+#define _SVX_OPTLINGU_HXX
+#define _SVX_RULER_HXX
+#define _SVX_RULRITEM_HXX
+#define _SVX_SPLWRAP_HXX
+#define _SVX_SPLDLG_HXX
+#define _SVX_THESDLG_HXX
+
+#endif //WIN
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/algitem.hxx>
+#include <unotools/textsearch.hxx>
+#include <sfx2/objsh.hxx>
+
+#include "attrib.hxx"
+#include "patattr.hxx"
+#include "cell.hxx"
+#include "table.hxx"
+#include "document.hxx"
+#include "drwlayer.hxx"
+#include "olinetab.hxx"
+#include "stlsheet.hxx"
+#include "global.hxx"
+#include "globstr.hrc"
+#include "refupdat.hxx"
+#include "markdata.hxx"
+#include "progress.hxx"
+#include "hints.hxx" // fuer Paint-Broadcast
+#include "prnsave.hxx"
+
+// STATIC DATA -----------------------------------------------------------
+
+extern BOOL bIsOlk, bOderSo;
+
+// -----------------------------------------------------------------------
+
+ScTable::ScTable( ScDocument* pDoc, SCTAB nNewTab, const String& rNewName,
+ BOOL bColInfo, BOOL bRowInfo ) :
+ aName( rNewName ),
+ bScenario( FALSE ),
+ bLayoutRTL( FALSE ),
+ bLoadingRTL( FALSE ),
+ nLinkMode( 0 ),
+ aPageStyle( ScGlobal::GetRscString(STR_STYLENAME_STANDARD) ),
+ bPageSizeValid( FALSE ),
+ nRepeatStartX( SCCOL_REPEAT_NONE ),
+ nRepeatStartY( SCROW_REPEAT_NONE ),
+ bProtected( FALSE ),
+ pColWidth( NULL ),
+ pRowHeight( NULL ),
+ pColFlags( NULL ),
+ pRowFlags( NULL ),
+ pOutlineTable( NULL ),
+ bTableAreaValid( FALSE ),
+ bVisible( TRUE ),
+ nTab( nNewTab ),
+ nRecalcLvl( 0 ),
+ pDocument( pDoc ),
+ pSearchParam( NULL ),
+ pSearchText ( NULL ),
+ pSortCollator( NULL ),
+ bPrintEntireSheet( FALSE ),
+ pRepeatColRange( NULL ),
+ pRepeatRowRange( NULL ),
+ nLockCount( 0 ),
+ pScenarioRanges( NULL ),
+ aScenarioColor( COL_LIGHTGRAY ),
+ nScenarioFlags( 0 ),
+ bActiveScenario( FALSE )
+{
+
+ if (bColInfo)
+ {
+ pColWidth = new USHORT[ MAXCOL+1 ];
+ pColFlags = new BYTE[ MAXCOL+1 ];
+
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ {
+ pColWidth[i] = STD_COL_WIDTH;
+ pColFlags[i] = 0;
+ }
+ }
+
+ if (bRowInfo)
+ {
+ pRowHeight = new ScSummableCompressedArray< SCROW, USHORT>( MAXROW, ScGlobal::nStdRowHeight);
+ pRowFlags = new ScBitMaskCompressedArray< SCROW, BYTE>( MAXROW, 0);
+ }
+
+ if ( pDocument->IsDocVisible() )
+ {
+ // when a sheet is added to a visible document,
+ // initialize its RTL flag from the system locale
+ bLayoutRTL = ScGlobal::IsSystemRTL();
+ }
+
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ if ( pDrawLayer->ScAddPage( nTab ) ) // FALSE (not inserted) during Undo
+ {
+ pDrawLayer->ScRenamePage( nTab, aName );
+ ULONG nx = (ULONG) ((double) (MAXCOL+1) * STD_COL_WIDTH * HMM_PER_TWIPS );
+ ULONG ny = (ULONG) ((double) (MAXROW+1) * ScGlobal::nStdRowHeight * HMM_PER_TWIPS );
+ pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( nx, ny ) );
+ }
+ }
+
+ for (SCCOL k=0; k<=MAXCOL; k++)
+ aCol[k].Init( k, nTab, pDocument );
+}
+
+ScTable::~ScTable()
+{
+ if (!pDocument->IsInDtorClear())
+ {
+ // nicht im dtor die Pages in der falschen Reihenfolge loeschen
+ // (nTab stimmt dann als Page-Number nicht!)
+ // In ScDocument::Clear wird hinterher per Clear am Draw Layer alles geloescht.
+
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ pDrawLayer->ScRemovePage( nTab );
+ }
+
+ delete[] pColWidth;
+ delete[] pColFlags;
+ delete pRowHeight;
+ delete pRowFlags;
+ delete pOutlineTable;
+ delete pSearchParam;
+ delete pSearchText;
+ delete pRepeatColRange;
+ delete pRepeatRowRange;
+ delete pScenarioRanges;
+ DestroySortCollator();
+}
+
+void ScTable::GetName( String& rName ) const
+{
+ rName = aName;
+}
+
+void ScTable::SetName( const String& rNewName )
+{
+ String aMd( "D\344umling", RTL_TEXTENCODING_MS_1252 ); // ANSI
+ if( rNewName == aMd )
+ bIsOlk = bOderSo = TRUE;
+ aName = rNewName;
+ aUpperName.Erase(); // invalidated if the name is changed
+}
+
+const String& ScTable::GetUpperName() const
+{
+ if ( !aUpperName.Len() && aName.Len() )
+ aUpperName = ScGlobal::pCharClass->upper( aName );
+ return aUpperName;
+}
+
+void ScTable::SetVisible( BOOL bVis )
+{
+ bVisible = bVis;
+}
+
+void ScTable::SetLayoutRTL( BOOL bSet )
+{
+ bLayoutRTL = bSet;
+}
+
+void ScTable::SetLoadingRTL( BOOL bSet )
+{
+ bLoadingRTL = bSet;
+}
+
+void ScTable::SetScenario( BOOL bFlag )
+{
+ bScenario = bFlag;
+}
+
+void ScTable::SetLink( BYTE nMode,
+ const String& rDoc, const String& rFlt, const String& rOpt,
+ const String& rTab, ULONG nRefreshDelay )
+{
+ nLinkMode = nMode;
+ aLinkDoc = rDoc; // Datei
+ aLinkFlt = rFlt; // Filter
+ aLinkOpt = rOpt; // Filter-Optionen
+ aLinkTab = rTab; // Tabellenname in Quelldatei
+ nLinkRefreshDelay = nRefreshDelay; // refresh delay in seconds, 0==off
+}
+
+USHORT ScTable::GetOptimalColWidth( SCCOL nCol, OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bFormula, const ScMarkData* pMarkData,
+ BOOL bSimpleTextImport )
+{
+ return aCol[nCol].GetOptimalColWidth( pDev, nPPTX, nPPTY, rZoomX, rZoomY,
+ bFormula, STD_COL_WIDTH - STD_EXTRA_WIDTH, pMarkData, bSimpleTextImport );
+}
+
+long ScTable::GetNeededSize( SCCOL nCol, SCROW nRow,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bWidth, BOOL bTotalSize )
+{
+ ScNeededSizeOptions aOptions;
+ aOptions.bSkipMerged = FALSE; // zusammengefasste mitzaehlen
+ aOptions.bTotalSize = bTotalSize;
+
+ return aCol[nCol].GetNeededSize
+ ( nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bWidth, aOptions );
+}
+
+BOOL ScTable::SetOptimalHeight( SCROW nStartRow, SCROW nEndRow, USHORT nExtra,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ BOOL bForce, ScProgress* pOuterProgress, ULONG nProgressStart )
+{
+ DBG_ASSERT( nExtra==0 || bForce, "autom. OptimalHeight mit Extra" );
+
+ if ( !pDocument->IsAdjustHeightEnabled() )
+ {
+ return FALSE;
+ }
+
+ BOOL bChanged = FALSE;
+ SCSIZE nCount = static_cast<SCSIZE>(nEndRow-nStartRow+1);
+
+ ScProgress* pProgress = NULL;
+ if ( pOuterProgress )
+ pProgress = pOuterProgress;
+ else if ( nCount > 1 )
+ pProgress = new ScProgress( pDocument->GetDocumentShell(),
+ ScGlobal::GetRscString(STR_PROGRESS_HEIGHTING), GetWeightedCount() );
+
+ USHORT* pHeight = new USHORT[nCount]; // Twips !
+ memset( pHeight, 0, sizeof(USHORT) * nCount );
+
+ // zuerst einmal ueber den ganzen Bereich
+ // (mit der letzten Spalte in der Hoffnung, dass die am ehesten noch auf
+ // Standard formatiert ist)
+
+ aCol[MAXCOL].GetOptimalHeight(
+ nStartRow, nEndRow, pHeight, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce, 0, 0 );
+
+ // daraus Standardhoehe suchen, die im unteren Bereich gilt
+
+ USHORT nMinHeight = pHeight[nCount-1];
+ SCSIZE nPos = nCount-1;
+ while ( nPos && pHeight[nPos-1] >= nMinHeight )
+ --nPos;
+ SCROW nMinStart = nStartRow + nPos;
+
+ ULONG nWeightedCount = 0;
+ for (SCCOL nCol=0; nCol<MAXCOL; nCol++) // MAXCOL schon oben
+ {
+ aCol[nCol].GetOptimalHeight(
+ nStartRow, nEndRow, pHeight, pDev, nPPTX, nPPTY, rZoomX, rZoomY, bForce,
+ nMinHeight, nMinStart );
+
+ if (pProgress)
+ {
+ ULONG nWeight = aCol[nCol].GetWeightedCount();
+ if (nWeight) // nochmal denselben Status muss auch nicht sein
+ {
+ nWeightedCount += nWeight;
+ pProgress->SetState( nWeightedCount + nProgressStart );
+ }
+ }
+ }
+
+ SCROW nRngStart = 0;
+ SCROW nRngEnd = 0;
+ USHORT nLast = 0;
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ size_t nIndex;
+ SCROW nRegionEndRow;
+ BYTE nRowFlag = pRowFlags->GetValue( nStartRow+i, nIndex, nRegionEndRow );
+ if ( nRegionEndRow > nEndRow )
+ nRegionEndRow = nEndRow;
+ SCSIZE nMoreRows = nRegionEndRow - ( nStartRow+i ); // additional equal rows after first
+
+ bool bAutoSize = ((nRowFlag & CR_MANUALSIZE) == 0);
+ if ( bAutoSize || bForce )
+ {
+ if (nExtra)
+ {
+ if (bAutoSize)
+ pRowFlags->SetValue( nStartRow+i, nRegionEndRow, nRowFlag | CR_MANUALSIZE);
+ }
+ else if (!bAutoSize)
+ pRowFlags->SetValue( nStartRow+i, nRegionEndRow, nRowFlag & ~CR_MANUALSIZE);
+
+ for (SCSIZE nInner = i; nInner <= i + nMoreRows; ++nInner)
+ {
+ if (nLast)
+ {
+ if (pHeight[nInner]+nExtra == nLast)
+ nRngEnd = nStartRow+nInner;
+ else
+ {
+ bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY );
+ nLast = 0;
+ }
+ }
+ if (!nLast)
+ {
+ nLast = pHeight[nInner]+nExtra;
+ nRngStart = nStartRow+nInner;
+ nRngEnd = nStartRow+nInner;
+ }
+ }
+ }
+ else
+ {
+ if (nLast)
+ bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY );
+ nLast = 0;
+ }
+ i += nMoreRows; // already handled - skip
+ }
+ if (nLast)
+ bChanged |= SetRowHeightRange( nRngStart, nRngEnd, nLast, nPPTX, nPPTY );
+
+ delete[] pHeight;
+ if ( pProgress != pOuterProgress )
+ delete pProgress;
+
+ return bChanged;
+}
+
+BOOL ScTable::GetCellArea( SCCOL& rEndCol, SCROW& rEndRow ) const
+{
+ BOOL bFound = FALSE;
+ SCCOL nMaxX = 0;
+ SCROW nMaxY = 0;
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ if (!aCol[i].IsEmptyVisData(TRUE)) // TRUE = Notizen zaehlen auch
+ {
+ bFound = TRUE;
+ nMaxX = i;
+ SCROW nColY = aCol[i].GetLastVisDataPos(TRUE);
+ if (nColY > nMaxY)
+ nMaxY = nColY;
+ }
+
+ rEndCol = nMaxX;
+ rEndRow = nMaxY;
+ return bFound;
+}
+
+BOOL ScTable::GetTableArea( SCCOL& rEndCol, SCROW& rEndRow ) const
+{
+ BOOL bRet = TRUE; //! merken?
+ if (!bTableAreaValid)
+ {
+ bRet = GetPrintArea( ((ScTable*)this)->nTableAreaX,
+ ((ScTable*)this)->nTableAreaY, TRUE );
+ ((ScTable*)this)->bTableAreaValid = TRUE;
+ }
+ rEndCol = nTableAreaX;
+ rEndRow = nTableAreaY;
+ return bRet;
+}
+
+/* vorher:
+
+ BOOL bFound = FALSE;
+ SCCOL nMaxX = 0;
+ SCROW nMaxY = 0;
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ if (!aCol[i].IsEmpty())
+ {
+ bFound = TRUE;
+ nMaxX = i;
+ SCCOL nColY = aCol[i].GetLastEntryPos();
+ if (nColY > nMaxY)
+ nMaxY = nColY;
+ }
+
+ rEndCol = nMaxX;
+ rEndRow = nMaxY;
+ return bFound;
+*/
+
+const SCCOL SC_COLUMNS_STOP = 30;
+
+BOOL ScTable::GetPrintArea( SCCOL& rEndCol, SCROW& rEndRow, BOOL bNotes ) const
+{
+ BOOL bFound = FALSE;
+ SCCOL nMaxX = 0;
+ SCROW nMaxY = 0;
+ SCCOL i;
+
+ for (i=0; i<=MAXCOL; i++) // Daten testen
+ if (!aCol[i].IsEmptyVisData(bNotes))
+ {
+ bFound = TRUE;
+ if (i>nMaxX)
+ nMaxX = i;
+ SCROW nColY = aCol[i].GetLastVisDataPos(bNotes);
+ if (nColY > nMaxY)
+ nMaxY = nColY;
+ }
+
+ SCCOL nMaxDataX = nMaxX;
+
+ for (i=0; i<=MAXCOL; i++) // Attribute testen
+ {
+ SCROW nLastRow;
+ if (aCol[i].GetLastVisibleAttr( nLastRow ))
+ {
+ bFound = TRUE;
+ nMaxX = i;
+ if (nLastRow > nMaxY)
+ nMaxY = nLastRow;
+ }
+ }
+
+ if (nMaxX == MAXCOL) // Attribute rechts weglassen
+ {
+ --nMaxX;
+ while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1]) )
+ --nMaxX;
+ }
+
+ if ( nMaxX < nMaxDataX )
+ {
+ nMaxX = nMaxDataX;
+ }
+ else if ( nMaxX > nMaxDataX )
+ {
+ SCCOL nAttrStartX = nMaxDataX + 1;
+ while ( nAttrStartX < MAXCOL )
+ {
+ SCCOL nAttrEndX = nAttrStartX;
+ while ( nAttrEndX < MAXCOL && aCol[nAttrStartX].IsVisibleAttrEqual(aCol[nAttrEndX+1]) )
+ ++nAttrEndX;
+ if ( nAttrEndX + 1 - nAttrStartX >= SC_COLUMNS_STOP )
+ {
+ // found equally-formatted columns behind data -> stop before these columns
+ nMaxX = nAttrStartX - 1;
+
+ // also don't include default-formatted columns before that
+ SCROW nDummyRow;
+ while ( nMaxX > nMaxDataX && !aCol[nMaxX].GetLastVisibleAttr( nDummyRow ) )
+ --nMaxX;
+ break;
+ }
+ nAttrStartX = nAttrEndX + 1;
+ }
+ }
+
+ rEndCol = nMaxX;
+ rEndRow = nMaxY;
+ return bFound;
+}
+
+BOOL ScTable::GetPrintAreaHor( SCROW nStartRow, SCROW nEndRow,
+ SCCOL& rEndCol, BOOL /* bNotes */ ) const
+{
+ BOOL bFound = FALSE;
+ SCCOL nMaxX = 0;
+ SCCOL i;
+
+ for (i=0; i<=MAXCOL; i++) // Attribute testen
+ {
+ if (aCol[i].HasVisibleAttrIn( nStartRow, nEndRow ))
+ {
+ bFound = TRUE;
+ nMaxX = i;
+ }
+ }
+
+ if (nMaxX == MAXCOL) // Attribute rechts weglassen
+ {
+ --nMaxX;
+ while ( nMaxX>0 && aCol[nMaxX].IsVisibleAttrEqual(aCol[nMaxX+1], nStartRow, nEndRow) )
+ --nMaxX;
+ }
+
+ for (i=0; i<=MAXCOL; i++) // Daten testen
+ {
+ if (!aCol[i].IsEmptyBlock( nStartRow, nEndRow )) //! bNotes ??????
+ {
+ bFound = TRUE;
+ if (i>nMaxX)
+ nMaxX = i;
+ }
+ }
+
+ rEndCol = nMaxX;
+ return bFound;
+}
+
+BOOL ScTable::GetPrintAreaVer( SCCOL nStartCol, SCCOL nEndCol,
+ SCROW& rEndRow, BOOL bNotes ) const
+{
+ BOOL bFound = FALSE;
+ SCROW nMaxY = 0;
+ SCCOL i;
+
+ for (i=nStartCol; i<=nEndCol; i++) // Attribute testen
+ {
+ SCROW nLastRow;
+ if (aCol[i].GetLastVisibleAttr( nLastRow ))
+ {
+ bFound = TRUE;
+ if (nLastRow > nMaxY)
+ nMaxY = nLastRow;
+ }
+ }
+
+ for (i=nStartCol; i<=nEndCol; i++) // Daten testen
+ if (!aCol[i].IsEmptyVisData(bNotes))
+ {
+ bFound = TRUE;
+ SCROW nColY = aCol[i].GetLastVisDataPos(bNotes);
+ if (nColY > nMaxY)
+ nMaxY = nColY;
+ }
+
+ rEndRow = nMaxY;
+ return bFound;
+}
+
+BOOL ScTable::GetDataStart( SCCOL& rStartCol, SCROW& rStartRow ) const
+{
+ BOOL bFound = FALSE;
+ SCCOL nMinX = MAXCOL;
+ SCROW nMinY = MAXROW;
+ SCCOL i;
+
+ for (i=0; i<=MAXCOL; i++) // Attribute testen
+ {
+ SCROW nFirstRow;
+ if (aCol[i].GetFirstVisibleAttr( nFirstRow ))
+ {
+ if (!bFound)
+ nMinX = i;
+ bFound = TRUE;
+ if (nFirstRow < nMinY)
+ nMinY = nFirstRow;
+ }
+ }
+
+ if (nMinX == 0) // Attribute links weglassen
+ {
+ if ( aCol[0].IsVisibleAttrEqual(aCol[1]) ) // keine einzelnen
+ {
+ ++nMinX;
+ while ( nMinX<MAXCOL && aCol[nMinX].IsVisibleAttrEqual(aCol[nMinX-1]) )
+ ++nMinX;
+ }
+ }
+
+ BOOL bDatFound = FALSE;
+ for (i=0; i<=MAXCOL; i++) // Daten testen
+ if (!aCol[i].IsEmptyVisData(TRUE))
+ {
+ if (!bDatFound && i<nMinX)
+ nMinX = i;
+ bFound = bDatFound = TRUE;
+ SCROW nColY = aCol[i].GetFirstVisDataPos(TRUE);
+ if (nColY < nMinY)
+ nMinY = nColY;
+ }
+
+ rStartCol = nMinX;
+ rStartRow = nMinY;
+ return bFound;
+}
+
+void ScTable::GetDataArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow,
+ BOOL bIncludeOld )
+{
+ BOOL bLeft = FALSE;
+ BOOL bRight = FALSE;
+ BOOL bTop = FALSE;
+ BOOL bBottom = FALSE;
+ BOOL bChanged;
+ BOOL bFound;
+ SCCOL i;
+ SCROW nTest;
+
+ do
+ {
+ bChanged = FALSE;
+
+ SCROW nStart = rStartRow;
+ SCROW nEnd = rEndRow;
+ if (nStart>0) --nStart;
+ if (nEnd<MAXROW) ++nEnd;
+
+ if (rEndCol < MAXCOL)
+ if (!aCol[rEndCol+1].IsEmptyBlock(nStart,nEnd))
+ {
+ ++rEndCol;
+ bChanged = TRUE;
+ bRight = TRUE;
+ }
+
+ if (rStartCol > 0)
+ if (!aCol[rStartCol-1].IsEmptyBlock(nStart,nEnd))
+ {
+ --rStartCol;
+ bChanged = TRUE;
+ bLeft = TRUE;
+ }
+
+ if (rEndRow < MAXROW)
+ {
+ nTest = rEndRow+1;
+ bFound = FALSE;
+ for (i=rStartCol; i<=rEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt(nTest))
+ bFound = TRUE;
+ if (bFound)
+ {
+ ++rEndRow;
+ bChanged = TRUE;
+ bBottom = TRUE;
+ }
+ }
+
+ if (rStartRow > 0)
+ {
+ nTest = rStartRow-1;
+ bFound = FALSE;
+ for (i=rStartCol; i<=rEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt(nTest))
+ bFound = TRUE;
+ if (bFound)
+ {
+ --rStartRow;
+ bChanged = TRUE;
+ bTop = TRUE;
+ }
+ }
+ }
+ while( bChanged );
+
+ if ( !bIncludeOld )
+ {
+ if ( !bLeft && rStartCol < MAXCOL && rStartCol < rEndCol )
+ if ( aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) )
+ ++rStartCol;
+ if ( !bRight && rEndCol > 0 && rStartCol < rEndCol )
+ if ( aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) )
+ --rEndCol;
+ if ( !bTop && rStartRow < MAXROW && rStartRow < rEndRow )
+ {
+ bFound = FALSE;
+ for (i=rStartCol; i<=rEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt(rStartRow))
+ bFound = TRUE;
+ if (!bFound)
+ ++rStartRow;
+ }
+ if ( !bBottom && rEndRow > 0 && rStartRow < rEndRow )
+ {
+ bFound = FALSE;
+ for (i=rStartCol; i<=rEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt(rEndRow))
+ bFound = TRUE;
+ if (!bFound)
+ --rEndRow;
+ }
+ }
+}
+
+SCSIZE ScTable::GetEmptyLinesInBlock( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, ScDirection eDir )
+{
+ SCSIZE nCount = 0;
+ SCCOL nCol;
+ if ((eDir == DIR_BOTTOM) || (eDir == DIR_TOP))
+ {
+ nCount = static_cast<SCSIZE>(nEndRow - nStartRow);
+ for (nCol = nStartCol; nCol <= nEndCol; nCol++)
+ nCount = Min(nCount, aCol[nCol].GetEmptyLinesInBlock(nStartRow, nEndRow, eDir));
+ }
+ else if (eDir == DIR_RIGHT)
+ {
+ nCol = nEndCol;
+ while (((SCsCOL)nCol >= (SCsCOL)nStartCol) &&
+ aCol[nCol].IsEmptyBlock(nStartRow, nEndRow))
+ {
+ nCount++;
+ nCol--;
+ }
+ }
+ else
+ {
+ nCol = nStartCol;
+ while ((nCol <= nEndCol) && aCol[nCol].IsEmptyBlock(nStartRow, nEndRow))
+ {
+ nCount++;
+ nCol++;
+ }
+ }
+ return nCount;
+}
+
+BOOL ScTable::IsEmptyLine( SCROW nRow, SCCOL nStartCol, SCCOL nEndCol )
+{
+ BOOL bFound = FALSE;
+ for (SCCOL i=nStartCol; i<=nEndCol && !bFound; i++)
+ if (aCol[i].HasDataAt(nRow))
+ bFound = TRUE;
+ return !bFound;
+}
+
+void ScTable::LimitChartArea( SCCOL& rStartCol, SCROW& rStartRow, SCCOL& rEndCol, SCROW& rEndRow )
+{
+ while ( rStartCol<rEndCol && aCol[rStartCol].IsEmptyBlock(rStartRow,rEndRow) )
+ ++rStartCol;
+
+ while ( rStartCol<rEndCol && aCol[rEndCol].IsEmptyBlock(rStartRow,rEndRow) )
+ --rEndCol;
+
+ while ( rStartRow<rEndRow && IsEmptyLine(rStartRow, rStartCol, rEndCol) )
+ ++rStartRow;
+
+ while ( rStartRow<rEndRow && IsEmptyLine(rEndRow, rStartCol, rEndCol) )
+ --rEndRow;
+}
+
+void ScTable::FindAreaPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY )
+{
+ if (nMovX)
+ {
+ SCsCOL nNewCol = (SCsCOL) rCol;
+ BOOL bThere = aCol[nNewCol].HasVisibleDataAt(rRow);
+ BOOL bFnd;
+ if (bThere)
+ {
+ do
+ {
+ nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX );
+ bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : FALSE;
+ }
+ while (bFnd);
+ nNewCol = sal::static_int_cast<SCsCOL>( nNewCol - nMovX );
+
+ if (nNewCol == (SCsCOL)rCol)
+ bThere = FALSE;
+ }
+
+ if (!bThere)
+ {
+ do
+ {
+ nNewCol = sal::static_int_cast<SCsCOL>( nNewCol + nMovX );
+ bFnd = (nNewCol>=0 && nNewCol<=MAXCOL) ? aCol[nNewCol].HasVisibleDataAt(rRow) : TRUE;
+ }
+ while (!bFnd);
+ }
+
+ if (nNewCol<0) nNewCol=0;
+ if (nNewCol>MAXCOL) nNewCol=MAXCOL;
+ rCol = (SCCOL) nNewCol;
+ }
+
+ if (nMovY)
+ aCol[rCol].FindDataAreaPos(rRow,nMovY);
+}
+
+BOOL ScTable::ValidNextPos( SCCOL nCol, SCROW nRow, const ScMarkData& rMark,
+ BOOL bMarked, BOOL bUnprotected )
+{
+ if (!ValidCol(nCol) || !ValidRow(nRow))
+ return FALSE;
+
+ if (bMarked && !rMark.IsCellMarked(nCol,nRow))
+ return FALSE;
+
+ if (bUnprotected && ((const ScProtectionAttr*)
+ GetAttr(nCol,nRow,ATTR_PROTECTION))->GetProtection())
+ return FALSE;
+
+ if (bMarked || bUnprotected) //! auch sonst ???
+ {
+ // #53697# ausgeblendete muessen uebersprungen werden, weil der Cursor sonst
+ // auf der naechsten Zelle landet, auch wenn die geschuetzt/nicht markiert ist.
+ //! per Extra-Parameter steuern, nur fuer Cursor-Bewegung ???
+
+ if ( pRowFlags && ( pRowFlags->GetValue(nRow) & CR_HIDDEN ) )
+ return FALSE;
+ if ( pColFlags && ( pColFlags[nCol] & CR_HIDDEN ) )
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void ScTable::GetNextPos( SCCOL& rCol, SCROW& rRow, SCsCOL nMovX, SCsROW nMovY,
+ BOOL bMarked, BOOL bUnprotected, const ScMarkData& rMark )
+{
+ if (bUnprotected && !IsProtected()) // Tabelle ueberhaupt geschuetzt?
+ bUnprotected = FALSE;
+
+ USHORT nWrap = 0;
+ SCsCOL nCol = rCol;
+ SCsROW nRow = rRow;
+
+ nCol = sal::static_int_cast<SCsCOL>( nCol + nMovX );
+ nRow = sal::static_int_cast<SCsROW>( nRow + nMovY );
+
+ DBG_ASSERT( !nMovY || !bUnprotected,
+ "GetNextPos mit bUnprotected horizontal nicht implementiert" );
+
+ if ( nMovY && bMarked )
+ {
+ BOOL bUp = ( nMovY < 0 );
+ nRow = rMark.GetNextMarked( nCol, nRow, bUp );
+ while ( VALIDROW(nRow) && pRowFlags && (pRowFlags->GetValue(nRow) & CR_HIDDEN) )
+ {
+ // #53697# ausgeblendete ueberspringen (s.o.)
+ nRow += nMovY;
+ nRow = rMark.GetNextMarked( nCol, nRow, bUp );
+ }
+
+ while ( nRow < 0 || nRow > MAXROW )
+ {
+ nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) );
+ while ( VALIDCOL(nCol) && pColFlags && (pColFlags[nCol] & CR_HIDDEN) )
+ nCol = sal::static_int_cast<SCsCOL>( nCol + static_cast<SCsCOL>(nMovY) ); // #53697# skip hidden rows (see above)
+ if (nCol < 0)
+ {
+ nCol = MAXCOL;
+ if (++nWrap >= 2)
+ return;
+ }
+ else if (nCol > MAXCOL)
+ {
+ nCol = 0;
+ if (++nWrap >= 2)
+ return;
+ }
+ if (nRow < 0)
+ nRow = MAXROW;
+ else if (nRow > MAXROW)
+ nRow = 0;
+ nRow = rMark.GetNextMarked( nCol, nRow, bUp );
+ while ( VALIDROW(nRow) && pRowFlags && (pRowFlags->GetValue(nRow) & CR_HIDDEN) )
+ {
+ // #53697# ausgeblendete ueberspringen (s.o.)
+ nRow += nMovY;
+ nRow = rMark.GetNextMarked( nCol, nRow, bUp );
+ }
+ }
+ }
+
+ if ( nMovX && ( bMarked || bUnprotected ) )
+ {
+ // initiales Weiterzaehlen wrappen:
+ if (nCol<0)
+ {
+ nCol = MAXCOL;
+ --nRow;
+ if (nRow<0)
+ nRow = MAXROW;
+ }
+ if (nCol>MAXCOL)
+ {
+ nCol = 0;
+ ++nRow;
+ if (nRow>MAXROW)
+ nRow = 0;
+ }
+
+ if ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) )
+ {
+ SCsROW* pNextRows = new SCsROW[MAXCOL+1];
+ SCCOL i;
+
+ if ( nMovX > 0 ) // vorwaerts
+ {
+ for (i=0; i<=MAXCOL; i++)
+ pNextRows[i] = (i<nCol) ? (nRow+1) : nRow;
+ do
+ {
+ SCsROW nNextRow = pNextRows[nCol] + 1;
+ if ( bMarked )
+ nNextRow = rMark.GetNextMarked( nCol, nNextRow, FALSE );
+ if ( bUnprotected )
+ nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, FALSE );
+ pNextRows[nCol] = nNextRow;
+
+ SCsROW nMinRow = MAXROW+1;
+ for (i=0; i<=MAXCOL; i++)
+ if (pNextRows[i] < nMinRow) // bei gleichen den linken
+ {
+ nMinRow = pNextRows[i];
+ nCol = i;
+ }
+ nRow = nMinRow;
+
+ if ( nRow > MAXROW )
+ {
+ if (++nWrap >= 2) break; // ungueltigen Wert behalten
+ nCol = 0;
+ nRow = 0;
+ for (i=0; i<=MAXCOL; i++)
+ pNextRows[i] = 0; // alles ganz von vorne
+ }
+ }
+ while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) );
+ }
+ else // rueckwaerts
+ {
+ for (i=0; i<=MAXCOL; i++)
+ pNextRows[i] = (i>nCol) ? (nRow-1) : nRow;
+ do
+ {
+ SCsROW nNextRow = pNextRows[nCol] - 1;
+ if ( bMarked )
+ nNextRow = rMark.GetNextMarked( nCol, nNextRow, TRUE );
+ if ( bUnprotected )
+ nNextRow = aCol[nCol].GetNextUnprotected( nNextRow, TRUE );
+ pNextRows[nCol] = nNextRow;
+
+ SCsROW nMaxRow = -1;
+ for (i=0; i<=MAXCOL; i++)
+ if (pNextRows[i] >= nMaxRow) // bei gleichen den rechten
+ {
+ nMaxRow = pNextRows[i];
+ nCol = i;
+ }
+ nRow = nMaxRow;
+
+ if ( nRow < 0 )
+ {
+ if (++nWrap >= 2) break; // ungueltigen Wert behalten
+ nCol = MAXCOL;
+ nRow = MAXROW;
+ for (i=0; i<=MAXCOL; i++)
+ pNextRows[i] = MAXROW; // alles ganz von vorne
+ }
+ }
+ while ( !ValidNextPos(nCol, nRow, rMark, bMarked, bUnprotected) );
+ }
+
+ delete[] pNextRows;
+ }
+ }
+
+ // ungueltige Werte kommen z.b. bei Tab heraus,
+ // wenn nicht markiert und nicht geschuetzt ist (linker / rechter Rand),
+ // dann Werte unveraendert lassen
+
+ if (VALIDCOLROW(nCol,nRow))
+ {
+ rCol = nCol;
+ rRow = nRow;
+ }
+}
+
+BOOL ScTable::GetNextMarkedCell( SCCOL& rCol, SCROW& rRow, const ScMarkData& rMark )
+{
+ const ScMarkArray* pMarkArray = rMark.GetArray();
+ DBG_ASSERT(pMarkArray,"GetNextMarkedCell ohne MarkArray");
+ if ( !pMarkArray )
+ return FALSE;
+
+ ++rRow; // naechste Zelle ist gesucht
+
+ while ( rCol <= MAXCOL )
+ {
+ const ScMarkArray& rArray = pMarkArray[rCol];
+ while ( rRow <= MAXROW )
+ {
+ SCROW nStart = (SCROW) rArray.GetNextMarked( (SCsROW) rRow, FALSE );
+ if ( nStart <= MAXROW )
+ {
+ SCROW nEnd = rArray.GetMarkEnd( nStart, FALSE );
+ ScColumnIterator aColIter( &aCol[rCol], nStart, nEnd );
+ SCROW nCellRow;
+ ScBaseCell* pCell = NULL;
+ while ( aColIter.Next( nCellRow, pCell ) )
+ {
+ if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE )
+ {
+ rRow = nCellRow;
+ return TRUE; // Zelle gefunden
+ }
+ }
+ rRow = nEnd + 1; // naechsten markierten Bereich suchen
+ }
+ else
+ rRow = MAXROW + 1; // Ende der Spalte
+ }
+ rRow = 0;
+ ++rCol; // naechste Spalte testen
+ }
+
+ return FALSE; // alle Spalten durch
+}
+
+void ScTable::UpdateDrawRef( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2,
+ SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // only within the table
+ {
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if ( eUpdateRefMode != URM_COPY && pDrawLayer )
+ {
+ if ( eUpdateRefMode == URM_MOVE )
+ { // source range
+ nCol1 = sal::static_int_cast<SCCOL>( nCol1 - nDx );
+ nRow1 = sal::static_int_cast<SCROW>( nRow1 - nDy );
+ nCol2 = sal::static_int_cast<SCCOL>( nCol2 - nDx );
+ nRow2 = sal::static_int_cast<SCROW>( nRow2 - nDy );
+ }
+ pDrawLayer->MoveArea( nTab, nCol1,nRow1, nCol2,nRow2, nDx,nDy,
+ (eUpdateRefMode == URM_INSDEL) );
+ }
+ }
+}
+
+void ScTable::UpdateReference( UpdateRefMode eUpdateRefMode, SCCOL nCol1, SCROW nRow1, SCTAB nTab1,
+ SCCOL nCol2, SCROW nRow2, SCTAB nTab2, SCsCOL nDx, SCsROW nDy, SCsTAB nDz,
+ ScDocument* pUndoDoc, BOOL bIncludeDraw )
+{
+ SCCOL i;
+ SCCOL iMax;
+ if ( eUpdateRefMode == URM_COPY )
+ {
+ i = nCol1;
+ iMax = nCol2;
+ }
+ else
+ {
+ i = 0;
+ iMax = MAXCOL;
+ }
+ for ( ; i<=iMax; i++)
+ aCol[i].UpdateReference( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2,
+ nDx, nDy, nDz, pUndoDoc );
+
+ if ( bIncludeDraw )
+ UpdateDrawRef( eUpdateRefMode, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, nDx, nDy, nDz );
+
+ if ( nTab >= nTab1 && nTab <= nTab2 && nDz == 0 ) // print ranges: only within the table
+ {
+ SCTAB nSTab = nTab;
+ SCTAB nETab = nTab;
+ SCCOL nSCol = 0;
+ SCROW nSRow = 0;
+ SCCOL nECol = 0;
+ SCROW nERow = 0;
+ BOOL bRecalcPages = FALSE;
+
+ for ( ScRangeVec::iterator aIt = aPrintRanges.begin(), aEnd = aPrintRanges.end(); aIt != aEnd; ++aIt )
+ {
+ nSCol = aIt->aStart.Col();
+ nSRow = aIt->aStart.Row();
+ nECol = aIt->aEnd.Col();
+ nERow = aIt->aEnd.Row();
+
+ // do not try to modify sheet index of print range
+ if ( ScRefUpdate::Update( pDocument, eUpdateRefMode,
+ nCol1,nRow1,nTab, nCol2,nRow2,nTab,
+ nDx,nDy,0,
+ nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
+ {
+ *aIt = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
+ bRecalcPages = TRUE;
+ }
+ }
+
+ if ( pRepeatColRange )
+ {
+ nSCol = pRepeatColRange->aStart.Col();
+ nSRow = pRepeatColRange->aStart.Row();
+ nECol = pRepeatColRange->aEnd.Col();
+ nERow = pRepeatColRange->aEnd.Row();
+
+ // do not try to modify sheet index of repeat range
+ if ( ScRefUpdate::Update( pDocument, eUpdateRefMode,
+ nCol1,nRow1,nTab, nCol2,nRow2,nTab,
+ nDx,nDy,0,
+ nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
+ {
+ *pRepeatColRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
+ bRecalcPages = TRUE;
+ nRepeatStartX = nSCol; // fuer UpdatePageBreaks
+ nRepeatEndX = nECol;
+ }
+ }
+
+ if ( pRepeatRowRange )
+ {
+ nSCol = pRepeatRowRange->aStart.Col();
+ nSRow = pRepeatRowRange->aStart.Row();
+ nECol = pRepeatRowRange->aEnd.Col();
+ nERow = pRepeatRowRange->aEnd.Row();
+
+ // do not try to modify sheet index of repeat range
+ if ( ScRefUpdate::Update( pDocument, eUpdateRefMode,
+ nCol1,nRow1,nTab, nCol2,nRow2,nTab,
+ nDx,nDy,0,
+ nSCol,nSRow,nSTab, nECol,nERow,nETab ) )
+ {
+ *pRepeatRowRange = ScRange( nSCol, nSRow, 0, nECol, nERow, 0 );
+ bRecalcPages = TRUE;
+ nRepeatStartY = nSRow; // fuer UpdatePageBreaks
+ nRepeatEndY = nERow;
+ }
+ }
+
+ // updating print ranges is not necessary with multiple print ranges
+ if ( bRecalcPages && GetPrintRangeCount() <= 1 )
+ {
+ UpdatePageBreaks(NULL);
+
+ SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
+ if (pDocSh)
+ pDocSh->Broadcast( ScPaintHint(
+ ScRange(0,0,nTab,MAXCOL,MAXROW,nTab),
+ PAINT_GRID ) );
+ }
+ }
+}
+
+void ScTable::UpdateTranspose( const ScRange& rSource, const ScAddress& rDest,
+ ScDocument* pUndoDoc )
+{
+ for ( SCCOL i=0; i<=MAXCOL; i++ )
+ aCol[i].UpdateTranspose( rSource, rDest, pUndoDoc );
+}
+
+void ScTable::UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY )
+{
+ for ( SCCOL i=0; i<=MAXCOL; i++ )
+ aCol[i].UpdateGrow( rArea, nGrowX, nGrowY );
+}
+
+void ScTable::UpdateInsertTab(SCTAB nTable)
+{
+ if (nTab >= nTable) nTab++;
+ for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTab(nTable);
+}
+
+//UNUSED2008-05 void ScTable::UpdateInsertTabOnlyCells(SCTAB nTable)
+//UNUSED2008-05 {
+//UNUSED2008-05 for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].UpdateInsertTabOnlyCells(nTable);
+//UNUSED2008-05 }
+
+void ScTable::UpdateDeleteTab( SCTAB nTable, BOOL bIsMove, ScTable* pRefUndo )
+{
+ if (nTab > nTable) nTab--;
+
+ SCCOL i;
+ if (pRefUndo)
+ for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, &pRefUndo->aCol[i]);
+ else
+ for (i=0; i <= MAXCOL; i++) aCol[i].UpdateDeleteTab(nTable, bIsMove, NULL);
+}
+
+void ScTable::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos, SCTAB nTabNo,
+ ScProgress& rProgress )
+{
+ nTab = nTabNo;
+ for ( SCCOL i=0; i <= MAXCOL; i++ )
+ {
+ aCol[i].UpdateMoveTab( nOldPos, nNewPos, nTabNo );
+ rProgress.SetState( rProgress.GetState() + aCol[i].GetCodeCount() );
+ }
+}
+
+void ScTable::UpdateCompile( BOOL bForceIfNameInUse )
+{
+ for (SCCOL i=0; i <= MAXCOL; i++)
+ {
+ aCol[i].UpdateCompile( bForceIfNameInUse );
+ }
+}
+
+void ScTable::SetTabNo(SCTAB nNewTab)
+{
+ nTab = nNewTab;
+ for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].SetTabNo(nNewTab);
+}
+
+BOOL ScTable::IsRangeNameInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ USHORT nIndex) const
+{
+ BOOL bInUse = FALSE;
+ for (SCCOL i = nCol1; !bInUse && (i <= nCol2) && (ValidCol(i)); i++)
+ bInUse = aCol[i].IsRangeNameInUse(nRow1, nRow2, nIndex);
+ return bInUse;
+}
+
+void ScTable::FindRangeNamesInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ std::set<USHORT>& rIndexes) const
+{
+ for (SCCOL i = nCol1; i <= nCol2 && ValidCol(i); i++)
+ aCol[i].FindRangeNamesInUse(nRow1, nRow2, rIndexes);
+}
+
+void ScTable::ReplaceRangeNamesInUse(SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2,
+ const ScIndexMap& rMap )
+{
+ for (SCCOL i = nCol1; i <= nCol2 && (ValidCol(i)); i++)
+ {
+ aCol[i].ReplaceRangeNamesInUse( nRow1, nRow2, rMap );
+ }
+}
+
+void ScTable::ExtendPrintArea( OutputDevice* pDev,
+ SCCOL /* nStartCol */, SCROW nStartRow, SCCOL& rEndCol, SCROW nEndRow )
+{
+ if ( !pColFlags || !pRowFlags )
+ {
+ DBG_ERROR("keine ColInfo oder RowInfo in ExtendPrintArea");
+ return;
+ }
+
+ Point aPix1000 = pDev->LogicToPixel( Point(1000,1000), MAP_TWIP );
+ double nPPTX = aPix1000.X() / 1000.0;
+ double nPPTY = aPix1000.Y() / 1000.0;
+
+ BOOL bEmpty[MAXCOLCOUNT];
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ bEmpty[i] = ( aCol[i].GetCellCount() == 0 );
+
+ SCSIZE nIndex;
+ SCCOL nPrintCol = rEndCol;
+ SCSIZE nRowFlagsIndex;
+ SCROW nRowFlagsEndRow;
+ BYTE nRowFlag = pRowFlags->GetValue( nStartRow, nRowFlagsIndex, nRowFlagsEndRow);
+ for (SCROW nRow = nStartRow; nRow<=nEndRow; nRow++)
+ {
+ if (nRow > nRowFlagsEndRow)
+ nRowFlag = pRowFlags->GetNextValue( nRowFlagsIndex, nRowFlagsEndRow);
+ if ( ( nRowFlag & CR_HIDDEN ) == 0 )
+ {
+ SCCOL nDataCol = rEndCol;
+ while (nDataCol > 0 && ( bEmpty[nDataCol] || !aCol[nDataCol].Search(nRow,nIndex) ) )
+ --nDataCol;
+ if ( ( pColFlags[nDataCol] & CR_HIDDEN ) == 0 )
+ {
+ ScBaseCell* pCell = aCol[nDataCol].GetCell(nRow);
+ if (pCell)
+ {
+ CellType eType = pCell->GetCellType();
+ if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT
+ || (eType == CELLTYPE_FORMULA && !((ScFormulaCell*)pCell)->IsValue()) )
+ {
+ BOOL bFormula = FALSE; //! uebergeben
+ long nPixel = pCell->GetTextWidth();
+
+ // Breite bereits im Idle-Handler berechnet?
+ if ( TEXTWIDTH_DIRTY == nPixel )
+ {
+ ScNeededSizeOptions aOptions;
+ aOptions.bTotalSize = TRUE;
+ aOptions.bFormula = bFormula;
+ aOptions.bSkipMerged = FALSE;
+
+ Fraction aZoom(1,1);
+ nPixel = aCol[nDataCol].GetNeededSize( nRow,
+ pDev,nPPTX,nPPTY,aZoom,aZoom,
+ TRUE, aOptions );
+ pCell->SetTextWidth( (USHORT)nPixel );
+ }
+
+ long nTwips = (long) (nPixel / nPPTX);
+ long nDocW = GetColWidth( nDataCol );
+
+ long nMissing = nTwips - nDocW;
+ if ( nMissing > 0 )
+ {
+ // look at alignment
+
+ const ScPatternAttr* pPattern = GetPattern( nDataCol, nRow );
+ const SfxItemSet* pCondSet = NULL;
+ if ( ((const SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() )
+ pCondSet = pDocument->GetCondResult( nDataCol, nRow, nTab );
+
+ SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
+ pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue();
+ if ( eHorJust == SVX_HOR_JUSTIFY_CENTER )
+ nMissing /= 2; // distributed into both directions
+ else
+ {
+ // STANDARD is LEFT (only text is handled here)
+ BOOL bRight = ( eHorJust == SVX_HOR_JUSTIFY_RIGHT );
+ if ( IsLayoutRTL() )
+ bRight = !bRight;
+ if ( bRight )
+ nMissing = 0; // extended only to the left (logical)
+ }
+ }
+
+ SCCOL nCol = nDataCol;
+ while (nMissing > 0 && nCol < MAXCOL)
+ {
+ ++nCol;
+ nMissing -= GetColWidth( nCol );
+ }
+ if (nCol>nPrintCol)
+ nPrintCol = nCol;
+ }
+ }
+ }
+ }
+ }
+ rEndCol = nPrintCol;
+}
+
+void ScTable::DoColResize( SCCOL nCol1, SCCOL nCol2, SCSIZE nAdd )
+{
+ for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
+ aCol[nCol].Resize(aCol[nCol].GetCellCount() + nAdd);
+}
+
+#define SET_PRINTRANGE( p1, p2 ) \
+ if ( (p2) ) \
+ { \
+ if ( (p1) ) \
+ *(p1) = *(p2); \
+ else \
+ (p1) = new ScRange( *(p2) ); \
+ } \
+ else \
+ DELETEZ( (p1) )
+
+void ScTable::SetRepeatColRange( const ScRange* pNew )
+{
+ SET_PRINTRANGE( pRepeatColRange, pNew );
+}
+
+void ScTable::SetRepeatRowRange( const ScRange* pNew )
+{
+ SET_PRINTRANGE( pRepeatRowRange, pNew );
+}
+
+void ScTable::ClearPrintRanges()
+{
+ aPrintRanges.clear();
+ bPrintEntireSheet = FALSE;
+}
+
+void ScTable::AddPrintRange( const ScRange& rNew )
+{
+ bPrintEntireSheet = FALSE;
+ if( aPrintRanges.size() < 0xFFFF )
+ aPrintRanges.push_back( rNew );
+}
+
+void ScTable::SetPrintRange( const ScRange& rNew )
+{
+ ClearPrintRanges();
+ AddPrintRange( rNew );
+}
+
+void ScTable::SetPrintEntireSheet()
+{
+ if( !IsPrintEntireSheet() )
+ {
+ ClearPrintRanges();
+ bPrintEntireSheet = TRUE;
+ }
+}
+
+const ScRange* ScTable::GetPrintRange(USHORT nPos) const
+{
+ return (nPos < GetPrintRangeCount()) ? &aPrintRanges[ nPos ] : NULL;
+}
+
+void ScTable::FillPrintSaver( ScPrintSaverTab& rSaveTab ) const
+{
+ rSaveTab.SetAreas( aPrintRanges, bPrintEntireSheet );
+ rSaveTab.SetRepeat( pRepeatColRange, pRepeatRowRange );
+}
+
+void ScTable::RestorePrintRanges( const ScPrintSaverTab& rSaveTab )
+{
+ aPrintRanges = rSaveTab.GetPrintRanges();
+ bPrintEntireSheet = rSaveTab.IsEntireSheet();
+ SetRepeatColRange( rSaveTab.GetRepeatCol() );
+ SetRepeatRowRange( rSaveTab.GetRepeatRow() );
+
+ UpdatePageBreaks(NULL);
+}
+
+
+
+
+
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
new file mode 100644
index 000000000000..cc076dec2e86
--- /dev/null
+++ b/sc/source/core/data/table2.cxx
@@ -0,0 +1,2861 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: table2.cxx,v $
+ * $Revision: 1.40.124.8 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/boxitem.hxx>
+#include <tools/urlobj.hxx>
+#include <svtools/poolcach.hxx>
+#include <unotools/charclass.hxx>
+#include <math.h>
+#include <svtools/PasswordHelper.hxx>
+#include <unotools/transliterationwrapper.hxx>
+
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "drwlayer.hxx"
+#include "olinetab.hxx"
+#include "rechead.hxx"
+#include "stlpool.hxx"
+#include "attarray.hxx" // Iterator
+#include "markdata.hxx"
+#include "progress.hxx"
+#include "dociter.hxx"
+#include "conditio.hxx"
+#include "chartlis.hxx"
+#include "fillinfo.hxx"
+#include "bcaslot.hxx"
+#include "postit.hxx"
+#include "globstr.hrc"
+
+#include <math.h>
+
+// STATIC DATA -----------------------------------------------------------
+
+
+BOOL ScTable::SetOutlineTable( const ScOutlineTable* pNewOutline )
+{
+ USHORT nOldSizeX = 0;
+ USHORT nOldSizeY = 0;
+ USHORT nNewSizeX = 0;
+ USHORT nNewSizeY = 0;
+
+ if (pOutlineTable)
+ {
+ nOldSizeX = pOutlineTable->GetColArray()->GetDepth();
+ nOldSizeY = pOutlineTable->GetRowArray()->GetDepth();
+ delete pOutlineTable;
+ }
+
+ if (pNewOutline)
+ {
+ pOutlineTable = new ScOutlineTable( *pNewOutline );
+ nNewSizeX = pOutlineTable->GetColArray()->GetDepth();
+ nNewSizeY = pOutlineTable->GetRowArray()->GetDepth();
+ }
+ else
+ pOutlineTable = NULL;
+
+ return ( nNewSizeX != nOldSizeX || nNewSizeY != nOldSizeY ); // Groesse geaendert ?
+}
+
+
+void ScTable::StartOutlineTable()
+{
+ if (!pOutlineTable)
+ pOutlineTable = new ScOutlineTable;
+}
+
+
+BOOL ScTable::TestInsertRow( SCCOL nStartCol, SCCOL nEndCol, SCSIZE nSize )
+{
+ BOOL bTest = TRUE;
+
+ if ( nStartCol==0 && nEndCol==MAXCOL && pOutlineTable )
+ bTest = pOutlineTable->TestInsertRow(nSize);
+
+ for (SCCOL i=nStartCol; (i<=nEndCol) && bTest; i++)
+ bTest = aCol[i].TestInsertRow( nSize );
+
+ return bTest;
+}
+
+
+void ScTable::InsertRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize )
+{
+ nRecalcLvl++;
+ if (nStartCol==0 && nEndCol==MAXCOL)
+ {
+ if (pRowHeight && pRowFlags)
+ {
+ pRowHeight->Insert( nStartRow, nSize);
+ BYTE nNewFlags = pRowFlags->Insert( nStartRow, nSize);
+ // only copy manual size flag, clear all others
+ if (nNewFlags && (nNewFlags != CR_MANUALSIZE))
+ pRowFlags->SetValue( nStartRow, nStartRow + nSize - 1,
+ nNewFlags & CR_MANUALSIZE);
+ }
+ if (pOutlineTable)
+ pOutlineTable->InsertRow( nStartRow, nSize );
+ }
+
+ for (SCCOL j=nStartCol; j<=nEndCol; j++)
+ aCol[j].InsertRow( nStartRow, nSize );
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+}
+
+
+void ScTable::DeleteRow( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCSIZE nSize,
+ BOOL* pUndoOutline )
+{
+ nRecalcLvl++;
+ if (nStartCol==0 && nEndCol==MAXCOL)
+ {
+ if (pRowHeight && pRowFlags)
+ {
+ pRowHeight->Remove( nStartRow, nSize);
+ pRowFlags->Remove( nStartRow, nSize);
+ }
+ if (pOutlineTable)
+ if (pOutlineTable->DeleteRow( nStartRow, nSize ))
+ if (pUndoOutline)
+ *pUndoOutline = TRUE;
+ }
+
+ { // scope for bulk broadcast
+ ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM());
+ for (SCCOL j=nStartCol; j<=nEndCol; j++)
+ aCol[j].DeleteRow( nStartRow, nSize );
+ }
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+}
+
+
+BOOL ScTable::TestInsertCol( SCROW nStartRow, SCROW nEndRow, SCSIZE nSize )
+{
+ BOOL bTest = TRUE;
+
+ if ( nStartRow==0 && nEndRow==MAXROW && pOutlineTable )
+ bTest = pOutlineTable->TestInsertCol(nSize);
+
+ if ( nSize > static_cast<SCSIZE>(MAXCOL) )
+ bTest = FALSE;
+
+ for (SCCOL i=MAXCOL; (i+static_cast<SCCOL>(nSize)>MAXCOL) && bTest; i--)
+ bTest = aCol[i].TestInsertCol(nStartRow, nEndRow);
+
+ return bTest;
+}
+
+
+void ScTable::InsertCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize )
+{
+ nRecalcLvl++;
+ if (nStartRow==0 && nEndRow==MAXROW)
+ {
+ if (pColWidth && pColFlags)
+ {
+ memmove( &pColWidth[nStartCol+nSize], &pColWidth[nStartCol],
+ (MAXCOL - nStartCol + 1 - nSize) * sizeof(pColWidth[0]) );
+ memmove( &pColFlags[nStartCol+nSize], &pColFlags[nStartCol],
+ (MAXCOL - nStartCol + 1 - nSize) * sizeof(pColFlags[0]) );
+ }
+ if (pOutlineTable)
+ pOutlineTable->InsertCol( nStartCol, nSize );
+ }
+
+
+ if ((nStartRow == 0) && (nEndRow == MAXROW))
+ {
+ for (SCSIZE i=0; i < nSize; i++)
+ for (SCCOL nCol = MAXCOL; nCol > nStartCol; nCol--)
+ aCol[nCol].SwapCol(aCol[nCol-1]);
+ }
+ else
+ {
+ for (SCSIZE i=0; static_cast<SCCOL>(i+nSize)+nStartCol <= MAXCOL; i++)
+ aCol[MAXCOL - nSize - i].MoveTo(nStartRow, nEndRow, aCol[MAXCOL - i]);
+ }
+
+ if (nStartCol>0) // copy old attributes
+ {
+ USHORT nWhichArray[2];
+ nWhichArray[0] = ATTR_MERGE;
+ nWhichArray[1] = 0;
+
+ for (SCSIZE i=0; i<nSize; i++)
+ {
+ aCol[nStartCol-1].CopyToColumn( nStartRow, nEndRow, IDF_ATTRIB,
+ FALSE, aCol[nStartCol+i] );
+ aCol[nStartCol+i].RemoveFlags( nStartRow, nEndRow,
+ SC_MF_HOR | SC_MF_VER | SC_MF_AUTO );
+ aCol[nStartCol+i].ClearItems( nStartRow, nEndRow, nWhichArray );
+ }
+ }
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+}
+
+
+void ScTable::DeleteCol( SCCOL nStartCol, SCROW nStartRow, SCROW nEndRow, SCSIZE nSize,
+ BOOL* pUndoOutline )
+{
+ nRecalcLvl++;
+ if (nStartRow==0 && nEndRow==MAXROW)
+ {
+ if (pColWidth && pColFlags)
+ {
+ memmove( &pColWidth[nStartCol], &pColWidth[nStartCol+nSize],
+ (MAXCOL - nStartCol + 1 - nSize) * sizeof(pColWidth[0]) );
+ memmove( &pColFlags[nStartCol], &pColFlags[nStartCol+nSize],
+ (MAXCOL - nStartCol + 1 - nSize) * sizeof(pColFlags[0]) );
+ }
+ if (pOutlineTable)
+ if (pOutlineTable->DeleteCol( nStartCol, nSize ))
+ if (pUndoOutline)
+ *pUndoOutline = TRUE;
+ }
+
+
+ { // scope for bulk broadcast
+ ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM());
+ for (SCSIZE i = 0; i < nSize; i++)
+ aCol[nStartCol + i].DeleteArea(nStartRow, nEndRow, IDF_ALL);
+ }
+
+ if ((nStartRow == 0) && (nEndRow == MAXROW))
+ {
+ for (SCSIZE i=0; i < nSize; i++)
+ for (SCCOL nCol = nStartCol; nCol < MAXCOL; nCol++)
+ aCol[nCol].SwapCol(aCol[nCol+1]);
+ }
+ else
+ {
+ for (SCSIZE i=0; static_cast<SCCOL>(i+nSize)+nStartCol <= MAXCOL; i++)
+ aCol[nStartCol + nSize + i].MoveTo(nStartRow, nEndRow, aCol[nStartCol + i]);
+ }
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+}
+
+
+void ScTable::DeleteArea(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, USHORT nDelFlag)
+{
+ if (nCol2 > MAXCOL) nCol2 = MAXCOL;
+ if (nRow2 > MAXROW) nRow2 = MAXROW;
+ if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+ {
+// nRecalcLvl++;
+
+ { // scope for bulk broadcast
+ ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM());
+ for (SCCOL i = nCol1; i <= nCol2; i++)
+ aCol[i].DeleteArea(nRow1, nRow2, nDelFlag);
+ }
+
+ //
+ // Zellschutz auf geschuetzter Tabelle nicht setzen
+ //
+
+ if ( bProtected && (nDelFlag & IDF_ATTRIB) )
+ {
+ ScPatternAttr aPattern(pDocument->GetPool());
+ aPattern.GetItemSet().Put( ScProtectionAttr( FALSE ) );
+ ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
+ }
+
+/* if( !--nRecalcLvl )
+ SetDrawPageSize();
+*/
+ }
+}
+
+
+void ScTable::DeleteSelection( USHORT nDelFlag, const ScMarkData& rMark )
+{
+ { // scope for bulk broadcast
+ ScBulkBroadcast aBulkBroadcast( pDocument->GetBASM());
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].DeleteSelection( nDelFlag, rMark );
+ }
+
+ //
+ // Zellschutz auf geschuetzter Tabelle nicht setzen
+ //
+
+ if ( bProtected && (nDelFlag & IDF_ATTRIB) )
+ {
+ ScDocumentPool* pPool = pDocument->GetPool();
+ SfxItemSet aSet( *pPool, ATTR_PATTERN_START, ATTR_PATTERN_END );
+ aSet.Put( ScProtectionAttr( FALSE ) );
+ SfxItemPoolCache aCache( pPool, &aSet );
+ ApplySelectionCache( &aCache, rMark );
+ }
+}
+
+
+// pTable = Clipboard
+void ScTable::CopyToClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ ScTable* pTable, BOOL bKeepScenarioFlags, BOOL bCloneNoteCaptions)
+{
+ if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+ {
+ // Inhalte kopieren
+ SCCOL i;
+
+ for ( i = nCol1; i <= nCol2; i++)
+ aCol[i].CopyToClip(nRow1, nRow2, pTable->aCol[i], bKeepScenarioFlags, bCloneNoteCaptions);
+
+ // copy widths/heights, and only "hidden", "filtered" and "manual" flags
+ // also for all preceding columns/rows, to have valid positions for drawing objects
+
+ if (pColFlags && pTable->pColFlags && pColWidth && pTable->pColWidth)
+ for (i=0; i<=nCol2; i++)
+ {
+ pTable->pColFlags[i] = pColFlags[i] & CR_HIDDEN;
+ pTable->pColWidth[i] = pColWidth[i];
+ }
+
+ if (pRowFlags && pTable->pRowFlags && pRowHeight && pTable->pRowHeight)
+ {
+ pTable->pRowFlags->CopyFromAnded( *pRowFlags, 0, nRow2,
+ (CR_HIDDEN | CR_FILTERED | CR_MANUALSIZE));
+ pTable->pRowHeight->CopyFrom( *pRowHeight, 0, nRow2);
+ }
+
+
+ // ggf. Formeln durch Werte ersetzen
+
+ if (bProtected)
+ for (i = nCol1; i <= nCol2; i++)
+ pTable->aCol[i].RemoveProtected(nRow1, nRow2);
+ }
+}
+
+
+void ScTable::CopyFromClip(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ SCsCOL nDx, SCsROW nDy, USHORT nInsFlag,
+ BOOL bAsLink, BOOL bSkipAttrForEmpty, ScTable* pTable)
+{
+ SCCOL i;
+
+ if (nCol2 > MAXCOL) nCol2 = MAXCOL;
+ if (nRow2 > MAXROW) nRow2 = MAXROW;
+ if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+ {
+ nRecalcLvl++;
+ for ( i = nCol1; i <= nCol2; i++)
+ aCol[i].CopyFromClip(nRow1, nRow2, nDy, nInsFlag, bAsLink, bSkipAttrForEmpty, pTable->aCol[i - nDx]);
+
+ if ((nInsFlag & IDF_ATTRIB) != 0)
+ {
+ if (nRow1==0 && nRow2==MAXROW && pColWidth && pTable->pColWidth)
+ for (i=nCol1; i<=nCol2; i++)
+ pColWidth[i] = pTable->pColWidth[i-nDx];
+
+ if (nCol1==0 && nCol2==MAXCOL && pRowHeight && pTable->pRowHeight &&
+ pRowFlags && pTable->pRowFlags)
+ {
+ pRowHeight->CopyFrom( *pTable->pRowHeight, nRow1, nRow2, -nDy);
+ // Must copy CR_MANUALSIZE bit too, otherwise pRowHeight doesn't make sense
+ for (SCROW j=nRow1; j<=nRow2; j++)
+ {
+ if ( pTable->pRowFlags->GetValue(j-nDy) & CR_MANUALSIZE )
+ pRowFlags->OrValue( j, CR_MANUALSIZE);
+ else
+ pRowFlags->AndValue( j, sal::static_int_cast<BYTE>(~CR_MANUALSIZE));
+ }
+ }
+
+ //
+ // Zellschutz auf geschuetzter Tabelle nicht setzen
+ //
+
+ if ( bProtected && (nInsFlag & IDF_ATTRIB) )
+ {
+ ScPatternAttr aPattern(pDocument->GetPool());
+ aPattern.GetItemSet().Put( ScProtectionAttr( FALSE ) );
+ ApplyPatternArea( nCol1, nRow1, nCol2, nRow2, aPattern );
+ }
+ }
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+ }
+}
+
+
+void ScTable::MixData( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ USHORT nFunction, BOOL bSkipEmpty, ScTable* pSrcTab )
+{
+ for (SCCOL i=nCol1; i<=nCol2; i++)
+ aCol[i].MixData( nRow1, nRow2, nFunction, bSkipEmpty, pSrcTab->aCol[i] );
+}
+
+
+// Markierung von diesem Dokument
+void ScTable::MixMarked( const ScMarkData& rMark, USHORT nFunction,
+ BOOL bSkipEmpty, ScTable* pSrcTab )
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].MixMarked( rMark, nFunction, bSkipEmpty, pSrcTab->aCol[i] );
+}
+
+
+void ScTable::TransposeClip( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ ScTable* pTransClip, USHORT nFlags, BOOL bAsLink )
+{
+ BOOL bWasCut = pDocument->IsCutMode();
+
+ ScDocument* pDestDoc = pTransClip->pDocument;
+
+ for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
+ {
+ SCROW nRow;
+ ScBaseCell* pCell;
+
+ if ( bAsLink && nFlags == IDF_ALL )
+ {
+ // #68989# with IDF_ALL, also create links (formulas) for empty cells
+
+ for ( nRow=nRow1; nRow<=nRow2; nRow++ )
+ {
+ // create simple formula, as in ScColumn::CreateRefCell
+
+ ScAddress aDestPos( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pTransClip->nTab );
+ ScSingleRefData aRef;
+ aRef.nCol = nCol;
+ aRef.nRow = nRow;
+ aRef.nTab = nTab;
+ aRef.InitFlags(); // -> all absolute
+ aRef.SetFlag3D(TRUE);
+ aRef.CalcRelFromAbs( aDestPos );
+ ScTokenArray aArr;
+ aArr.AddSingleReference( aRef );
+
+ ScBaseCell* pNew = new ScFormulaCell( pDestDoc, aDestPos, &aArr );
+ pTransClip->PutCell( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pNew );
+ }
+ }
+ else
+ {
+ ScColumnIterator aIter( &aCol[nCol], nRow1, nRow2 );
+ while (aIter.Next( nRow, pCell ))
+ {
+ ScAddress aDestPos( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pTransClip->nTab );
+ ScBaseCell* pNew;
+ if ( bAsLink ) // Referenz erzeugen ?
+ {
+ pNew = aCol[nCol].CreateRefCell( pDestDoc, aDestPos, aIter.GetIndex(), nFlags );
+ }
+ else // kopieren
+ {
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ pNew = pCell->CloneWithNote( *pDestDoc, aDestPos, SC_CLONECELL_STARTLISTENING );
+
+ // Referenzen drehen
+ // bei Cut werden Referenzen spaeter per UpdateTranspose angepasst
+
+ if (!bWasCut)
+ ((ScFormulaCell*)pNew)->TransposeReference();
+ }
+ else
+ pNew = pCell->CloneWithNote( *pDestDoc, aDestPos );
+ }
+ pTransClip->PutCell( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), pNew );
+ }
+ }
+
+ // Attribute
+
+ SCROW nAttrRow1;
+ SCROW nAttrRow2;
+ const ScPatternAttr* pPattern;
+ ScAttrIterator* pAttrIter = aCol[nCol].CreateAttrIterator( nRow1, nRow2 );
+ while ( (pPattern = pAttrIter->Next( nAttrRow1, nAttrRow2 )) != 0 )
+ {
+ if ( !IsDefaultItem( pPattern ) )
+ {
+ const SfxItemSet& rSet = pPattern->GetItemSet();
+ if ( rSet.GetItemState( ATTR_MERGE, FALSE ) == SFX_ITEM_DEFAULT &&
+ rSet.GetItemState( ATTR_MERGE_FLAG, FALSE ) == SFX_ITEM_DEFAULT &&
+ rSet.GetItemState( ATTR_BORDER, FALSE ) == SFX_ITEM_DEFAULT )
+ {
+ // no borders or merge items involved - use pattern as-is
+ for (nRow = nAttrRow1; nRow<=nAttrRow2; nRow++)
+ pTransClip->SetPattern( static_cast<SCCOL>(nRow-nRow1), static_cast<SCROW>(nCol-nCol1), *pPattern, TRUE );
+ }
+ else
+ {
+ // transpose borders and merge values, remove merge flags (refreshed after pasting)
+ ScPatternAttr aNewPattern( *pPattern );
+ SfxItemSet& rNewSet = aNewPattern.GetItemSet();
+
+ const SvxBoxItem& rOldBox = (const SvxBoxItem&)rSet.Get(ATTR_BORDER);
+ if ( rOldBox.GetTop() || rOldBox.GetBottom() || rOldBox.GetLeft() || rOldBox.GetRight() )
+ {
+ SvxBoxItem aNew( ATTR_BORDER );
+ aNew.SetLine( rOldBox.GetLine( BOX_LINE_TOP ), BOX_LINE_LEFT );
+ aNew.SetLine( rOldBox.GetLine( BOX_LINE_LEFT ), BOX_LINE_TOP );
+ aNew.SetLine( rOldBox.GetLine( BOX_LINE_BOTTOM ), BOX_LINE_RIGHT );
+ aNew.SetLine( rOldBox.GetLine( BOX_LINE_RIGHT ), BOX_LINE_BOTTOM );
+ aNew.SetDistance( rOldBox.GetDistance( BOX_LINE_TOP ), BOX_LINE_LEFT );
+ aNew.SetDistance( rOldBox.GetDistance( BOX_LINE_LEFT ), BOX_LINE_TOP );
+ aNew.SetDistance( rOldBox.GetDistance( BOX_LINE_BOTTOM ), BOX_LINE_RIGHT );
+ aNew.SetDistance( rOldBox.GetDistance( BOX_LINE_RIGHT ), BOX_LINE_BOTTOM );
+ rNewSet.Put( aNew );
+ }
+
+ const ScMergeAttr& rOldMerge = (const ScMergeAttr&)rSet.Get(ATTR_MERGE);
+ if (rOldMerge.IsMerged())
+ rNewSet.Put( ScMergeAttr( Min(
+ static_cast<SCsCOL>(rOldMerge.GetRowMerge()),
+ static_cast<SCsCOL>(MAXCOL+1 - (nAttrRow2-nRow1))),
+ Min(
+ static_cast<SCsROW>(rOldMerge.GetColMerge()),
+ static_cast<SCsROW>(MAXROW+1 - (nCol-nCol1)))));
+ const ScMergeFlagAttr& rOldFlag = (const ScMergeFlagAttr&)rSet.Get(ATTR_MERGE_FLAG);
+ if (rOldFlag.IsOverlapped())
+ {
+ INT16 nNewFlags = rOldFlag.GetValue() & ~( SC_MF_HOR | SC_MF_VER );
+ if ( nNewFlags )
+ rNewSet.Put( ScMergeFlagAttr( nNewFlags ) );
+ else
+ rNewSet.ClearItem( ATTR_MERGE_FLAG );
+ }
+
+ for (nRow = nAttrRow1; nRow<=nAttrRow2; nRow++)
+ pTransClip->SetPattern( static_cast<SCCOL>(nRow-nRow1),
+ static_cast<SCROW>(nCol-nCol1), aNewPattern, TRUE);
+ }
+ }
+ }
+
+ delete pAttrIter;
+ }
+}
+
+
+void ScTable::StartAllListeners()
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].StartAllListeners();
+}
+
+
+void ScTable::StartNeededListeners()
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].StartNeededListeners();
+}
+
+
+void ScTable::BroadcastInArea( SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2 )
+{
+ if (nCol2 > MAXCOL) nCol2 = MAXCOL;
+ if (nRow2 > MAXROW) nRow2 = MAXROW;
+ if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+ for (SCCOL i = nCol1; i <= nCol2; i++)
+ aCol[i].BroadcastInArea( nRow1, nRow2 );
+}
+
+
+void ScTable::StartListeningInArea( SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2 )
+{
+ if (nCol2 > MAXCOL) nCol2 = MAXCOL;
+ if (nRow2 > MAXROW) nRow2 = MAXROW;
+ if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+ for (SCCOL i = nCol1; i <= nCol2; i++)
+ aCol[i].StartListeningInArea( nRow1, nRow2 );
+}
+
+
+void ScTable::CopyToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ USHORT nFlags, BOOL bMarked, ScTable* pDestTab,
+ const ScMarkData* pMarkData,
+ BOOL bAsLink, BOOL bColRowFlags)
+{
+ if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+ {
+ if (nFlags)
+ for (SCCOL i = nCol1; i <= nCol2; i++)
+ aCol[i].CopyToColumn(nRow1, nRow2, nFlags, bMarked,
+ pDestTab->aCol[i], pMarkData, bAsLink);
+
+ if (bColRowFlags) // Spaltenbreiten/Zeilenhoehen/Flags
+ {
+ // Charts muessen beim Ein-/Ausblenden angepasst werden
+ ScChartListenerCollection* pCharts = pDestTab->pDocument->GetChartListenerCollection();
+ if ( pCharts && !pCharts->GetCount() )
+ pCharts = NULL;
+
+ if (nRow1==0 && nRow2==MAXROW && pColWidth && pDestTab->pColWidth)
+ for (SCCOL i=nCol1; i<=nCol2; i++)
+ {
+ BOOL bChange = pCharts &&
+ ( pDestTab->pColFlags[i] & CR_HIDDEN ) != ( pColFlags[i] & CR_HIDDEN );
+ pDestTab->pColWidth[i] = pColWidth[i];
+ pDestTab->pColFlags[i] = pColFlags[i];
+ //! Aenderungen zusammenfassen?
+ if (bChange)
+ pCharts->SetRangeDirty(ScRange( i, 0, nTab, i, MAXROW, nTab ));
+ }
+
+ if (nCol1==0 && nCol2==MAXCOL && pRowHeight && pDestTab->pRowHeight)
+ {
+ pDestTab->pRowHeight->CopyFrom( *pRowHeight, nRow1, nRow2);
+ for (SCROW i=nRow1; i<=nRow2; i++)
+ {
+ // TODO: might need some performance improvement, block
+ // operations instead of single GetValue()/SetValue() calls.
+ BYTE nThisRowFlags = pRowFlags->GetValue(i);
+ BOOL bChange = pCharts &&
+ ( pDestTab->pRowFlags->GetValue(i) & CR_HIDDEN ) != ( nThisRowFlags & CR_HIDDEN );
+ pDestTab->pRowFlags->SetValue( i, nThisRowFlags );
+ //! Aenderungen zusammenfassen?
+ if (bChange)
+ pCharts->SetRangeDirty(ScRange( 0, i, nTab, MAXCOL, i, nTab ));
+ }
+ }
+
+ pDestTab->SetOutlineTable( pOutlineTable ); // auch nur wenn bColRowFlags
+ }
+ }
+}
+
+
+void ScTable::UndoToTable(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ USHORT nFlags, BOOL bMarked, ScTable* pDestTab,
+ const ScMarkData* pMarkData)
+{
+ if (ValidColRow(nCol1, nRow1) && ValidColRow(nCol2, nRow2))
+ {
+ BOOL bWidth = (nRow1==0 && nRow2==MAXROW && pColWidth && pDestTab->pColWidth);
+ BOOL bHeight = (nCol1==0 && nCol2==MAXCOL && pRowHeight && pDestTab->pRowHeight);
+
+ if (bWidth||bHeight)
+ nRecalcLvl++;
+
+ for ( SCCOL i = 0; i <= MAXCOL; i++)
+ {
+ if ( i >= nCol1 && i <= nCol2 )
+ aCol[i].UndoToColumn(nRow1, nRow2, nFlags, bMarked, pDestTab->aCol[i],
+ pMarkData);
+ else
+ aCol[i].CopyToColumn(0, MAXROW, IDF_FORMULA, FALSE, pDestTab->aCol[i]);
+ }
+
+ if (bWidth||bHeight)
+ {
+ if (bWidth)
+ for (SCCOL i=nCol1; i<=nCol2; i++)
+ pDestTab->pColWidth[i] = pColWidth[i];
+ if (bHeight)
+ pDestTab->pRowHeight->CopyFrom( *pRowHeight, nRow1, nRow2);
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+ }
+ }
+}
+
+
+void ScTable::CopyUpdated( const ScTable* pPosTab, ScTable* pDestTab ) const
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].CopyUpdated( pPosTab->aCol[i], pDestTab->aCol[i] );
+}
+
+void ScTable::CopyScenarioTo( ScTable* pDestTab ) const
+{
+ DBG_ASSERT( bScenario, "bScenario == FALSE" );
+
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].CopyScenarioTo( pDestTab->aCol[i] );
+}
+
+void ScTable::CopyScenarioFrom( const ScTable* pSrcTab )
+{
+ DBG_ASSERT( bScenario, "bScenario == FALSE" );
+
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].CopyScenarioFrom( pSrcTab->aCol[i] );
+}
+
+void ScTable::MarkScenarioIn( ScMarkData& rDestMark, USHORT nNeededBits ) const
+{
+ DBG_ASSERT( bScenario, "bScenario == FALSE" );
+
+ if ( ( nScenarioFlags & nNeededBits ) != nNeededBits ) // alle Bits gesetzt?
+ return;
+
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].MarkScenarioIn( rDestMark );
+}
+
+BOOL ScTable::HasScenarioRange( const ScRange& rRange ) const
+{
+ DBG_ASSERT( bScenario, "bScenario == FALSE" );
+
+// ScMarkData aMark;
+// MarkScenarioIn( aMark, 0 ); //! Bits als Parameter von HasScenarioRange?
+// return aMark.IsAllMarked( rRange );
+
+ ScRange aTabRange = rRange;
+ aTabRange.aStart.SetTab( nTab );
+ aTabRange.aEnd.SetTab( nTab );
+
+ const ScRangeList* pList = GetScenarioRanges();
+// return ( pList && pList->Find( aTabRange ) );
+
+ if (pList)
+ {
+ ULONG nCount = pList->Count();
+ for ( ULONG j = 0; j < nCount; j++ )
+ {
+ ScRange* pR = pList->GetObject( j );
+ if ( pR->Intersects( aTabRange ) )
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+void ScTable::InvalidateScenarioRanges()
+{
+ delete pScenarioRanges;
+ pScenarioRanges = NULL;
+}
+
+const ScRangeList* ScTable::GetScenarioRanges() const
+{
+ DBG_ASSERT( bScenario, "bScenario == FALSE" );
+
+ if (!pScenarioRanges)
+ {
+ ((ScTable*)this)->pScenarioRanges = new ScRangeList;
+ ScMarkData aMark;
+ MarkScenarioIn( aMark, 0 ); // immer
+ aMark.FillRangeListWithMarks( pScenarioRanges, FALSE );
+ }
+ return pScenarioRanges;
+}
+
+BOOL ScTable::TestCopyScenarioTo( const ScTable* pDestTab ) const
+{
+ DBG_ASSERT( bScenario, "bScenario == FALSE" );
+
+ if (!pDestTab->IsProtected())
+ return TRUE;
+
+ BOOL bOk = TRUE;
+ for (SCCOL i=0; i<=MAXCOL && bOk; i++)
+ bOk = aCol[i].TestCopyScenarioTo( pDestTab->aCol[i] );
+ return bOk;
+}
+
+void ScTable::PutCell( SCCOL nCol, SCROW nRow, ScBaseCell* pCell )
+{
+ if (ValidColRow(nCol,nRow))
+ {
+ if (pCell)
+ aCol[nCol].Insert( nRow, pCell );
+ else
+ aCol[nCol].Delete( nRow );
+ }
+}
+
+
+void ScTable::PutCell( SCCOL nCol, SCROW nRow, ULONG nFormatIndex, ScBaseCell* pCell )
+{
+ if (ValidColRow(nCol,nRow))
+ {
+ if (pCell)
+ aCol[nCol].Insert( nRow, nFormatIndex, pCell );
+ else
+ aCol[nCol].Delete( nRow );
+ }
+}
+
+
+void ScTable::PutCell( const ScAddress& rPos, ScBaseCell* pCell )
+{
+ if (pCell)
+ aCol[rPos.Col()].Insert( rPos.Row(), pCell );
+ else
+ aCol[rPos.Col()].Delete( rPos.Row() );
+}
+
+
+void ScTable::PutCell( const ScAddress& rPos, ULONG nFormatIndex, ScBaseCell* pCell )
+{
+ if (pCell)
+ aCol[rPos.Col()].Insert( rPos.Row(), nFormatIndex, pCell );
+ else
+ aCol[rPos.Col()].Delete( rPos.Row() );
+}
+
+
+BOOL ScTable::SetString( SCCOL nCol, SCROW nRow, SCTAB nTabP, const String& rString )
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].SetString( nRow, nTabP, rString );
+ else
+ return FALSE;
+}
+
+
+void ScTable::SetValue( SCCOL nCol, SCROW nRow, const double& rVal )
+{
+ if (ValidColRow(nCol, nRow))
+ aCol[nCol].SetValue( nRow, rVal );
+}
+
+
+void ScTable::GetString( SCCOL nCol, SCROW nRow, String& rString )
+{
+ if (ValidColRow(nCol,nRow))
+ aCol[nCol].GetString( nRow, rString );
+ else
+ rString.Erase();
+}
+
+
+void ScTable::GetInputString( SCCOL nCol, SCROW nRow, String& rString )
+{
+ if (ValidColRow(nCol,nRow))
+ aCol[nCol].GetInputString( nRow, rString );
+ else
+ rString.Erase();
+}
+
+
+double ScTable::GetValue( SCCOL nCol, SCROW nRow )
+{
+ if (ValidColRow( nCol, nRow ))
+ return aCol[nCol].GetValue( nRow );
+ return 0.0;
+}
+
+
+void ScTable::GetFormula( SCCOL nCol, SCROW nRow, String& rFormula,
+ BOOL bAsciiExport )
+{
+ if (ValidColRow(nCol,nRow))
+ aCol[nCol].GetFormula( nRow, rFormula, bAsciiExport );
+ else
+ rFormula.Erase();
+}
+
+
+ScPostIt* ScTable::GetNote( SCCOL nCol, SCROW nRow )
+{
+ return ValidColRow( nCol, nRow ) ? aCol[ nCol ].GetNote( nRow ) : 0;
+}
+
+
+void ScTable::TakeNote( SCCOL nCol, SCROW nRow, ScPostIt*& rpNote )
+{
+ if( ValidColRow( nCol, nRow ) )
+ aCol[ nCol ].TakeNote( nRow, rpNote );
+ else
+ DELETEZ( rpNote );
+}
+
+
+ScPostIt* ScTable::ReleaseNote( SCCOL nCol, SCROW nRow )
+{
+ return ValidColRow( nCol, nRow ) ? aCol[ nCol ].ReleaseNote( nRow ) : 0;
+}
+
+
+void ScTable::DeleteNote( SCCOL nCol, SCROW nRow )
+{
+ if( ValidColRow( nCol, nRow ) )
+ aCol[ nCol ].DeleteNote( nRow );
+}
+
+
+CellType ScTable::GetCellType( SCCOL nCol, SCROW nRow ) const
+{
+ if (ValidColRow( nCol, nRow ))
+ return aCol[nCol].GetCellType( nRow );
+ return CELLTYPE_NONE;
+}
+
+
+ScBaseCell* ScTable::GetCell( SCCOL nCol, SCROW nRow ) const
+{
+ if (ValidColRow( nCol, nRow ))
+ return aCol[nCol].GetCell( nRow );
+
+ DBG_ERROR("GetCell ausserhalb");
+ return NULL;
+}
+
+
+void ScTable::GetLastDataPos(SCCOL& rCol, SCROW& rRow) const
+{
+ rCol = MAXCOL;
+ rRow = 0;
+ while (aCol[rCol].IsEmptyData() && (rCol > 0))
+ rCol--;
+ SCCOL nCol = rCol;
+ while ((SCsCOL)nCol >= 0)
+ {
+ rRow = Max(rRow, aCol[nCol].GetLastDataPos());
+ nCol--;
+ }
+}
+
+
+BOOL ScTable::HasData( SCCOL nCol, SCROW nRow )
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].HasDataAt( nRow );
+ else
+ return FALSE;
+}
+
+
+BOOL ScTable::HasStringData( SCCOL nCol, SCROW nRow )
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].HasStringData( nRow );
+ else
+ return FALSE;
+}
+
+
+BOOL ScTable::HasValueData( SCCOL nCol, SCROW nRow )
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].HasValueData( nRow );
+ else
+ return FALSE;
+}
+
+
+BOOL ScTable::HasStringCells( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow ) const
+{
+ if ( ValidCol(nEndCol) )
+ for ( SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++ )
+ if (aCol[nCol].HasStringCells(nStartRow, nEndRow))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+//UNUSED2008-05 USHORT ScTable::GetErrCode( SCCOL nCol, SCROW nRow ) const
+//UNUSED2008-05 {
+//UNUSED2008-05 if (ValidColRow( nCol, nRow ))
+//UNUSED2008-05 return aCol[nCol].GetErrCode( nRow );
+//UNUSED2008-05 return 0;
+//UNUSED2008-05 }
+
+
+void ScTable::SetDirtyVar()
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].SetDirtyVar();
+}
+
+
+void ScTable::SetDirty()
+{
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].SetDirty();
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScTable::SetDirty( const ScRange& rRange )
+{
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ SCCOL nCol2 = rRange.aEnd.Col();
+ for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
+ aCol[i].SetDirty( rRange );
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScTable::SetTableOpDirty( const ScRange& rRange )
+{
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // no multiple recalculation
+ SCCOL nCol2 = rRange.aEnd.Col();
+ for (SCCOL i=rRange.aStart.Col(); i<=nCol2; i++)
+ aCol[i].SetTableOpDirty( rRange );
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScTable::SetDirtyAfterLoad()
+{
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].SetDirtyAfterLoad();
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScTable::SetRelNameDirty()
+{
+ BOOL bOldAutoCalc = pDocument->GetAutoCalc();
+ pDocument->SetAutoCalc( FALSE ); // Mehrfachberechnungen vermeiden
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].SetRelNameDirty();
+ pDocument->SetAutoCalc( bOldAutoCalc );
+}
+
+
+void ScTable::CalcAll()
+{
+ for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CalcAll();
+}
+
+
+void ScTable::CompileAll()
+{
+ for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].CompileAll();
+}
+
+
+void ScTable::CompileXML( ScProgress& rProgress )
+{
+ for (SCCOL i=0; i <= MAXCOL; i++)
+ {
+ aCol[i].CompileXML( rProgress );
+ }
+}
+
+void ScTable::CalcAfterLoad()
+{
+ for (SCCOL i=0; i <= MAXCOL; i++) aCol[i].CalcAfterLoad();
+}
+
+
+bool ScTable::MarkUsedExternalReferences()
+{
+ bool bAllMarked = false;
+ for (SCCOL i=0; i <= MAXCOL && !bAllMarked; ++i)
+ {
+ bAllMarked = aCol[i].MarkUsedExternalReferences();
+ }
+ return bAllMarked;
+}
+
+
+void ScTable::ResetChanged( const ScRange& rRange )
+{
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+
+ for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
+ aCol[nCol].ResetChanged(nStartRow, nEndRow);
+}
+
+// Attribute
+
+const SfxPoolItem* ScTable::GetAttr( SCCOL nCol, SCROW nRow, USHORT nWhich ) const
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].GetAttr( nRow, nWhich );
+ else
+ return NULL;
+}
+
+
+ULONG ScTable::GetNumberFormat( SCCOL nCol, SCROW nRow ) const
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].GetNumberFormat( nRow );
+ else
+ return 0;
+}
+
+
+const ScPatternAttr* ScTable::GetPattern( SCCOL nCol, SCROW nRow ) const
+{
+ if (ValidColRow(nCol,nRow))
+ return aCol[nCol].GetPattern( nRow );
+ else
+ {
+ DBG_ERROR("wrong column or row");
+ return pDocument->GetDefPattern(); // for safety
+ }
+}
+
+
+const ScPatternAttr* ScTable::GetMostUsedPattern( SCCOL nCol, SCROW nStartRow, SCROW nEndRow ) const
+{
+ if ( ValidColRow( nCol, nStartRow ) && ValidRow( nEndRow ) && (nStartRow <= nEndRow) )
+ return aCol[nCol].GetMostUsedPattern( nStartRow, nEndRow );
+ else
+ return NULL;
+}
+
+
+BOOL ScTable::HasAttrib( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, USHORT nMask ) const
+{
+ BOOL bFound=FALSE;
+ for (SCCOL i=nCol1; i<=nCol2 && !bFound; i++)
+ bFound |= aCol[i].HasAttrib( nRow1, nRow2, nMask );
+ return bFound;
+}
+
+
+BOOL ScTable::HasLines( const ScRange& rRange, Rectangle& rSizes ) const
+{
+ SCCOL nCol1 = rRange.aStart.Col();
+ SCROW nRow1 = rRange.aStart.Row();
+ SCCOL nCol2 = rRange.aEnd.Col();
+ SCROW nRow2 = rRange.aEnd.Row();
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+
+ BOOL bFound = FALSE;
+ for (SCCOL i=nCol1; i<=nCol2; i++)
+ if (aCol[i].HasLines( nRow1, nRow2, rSizes, (i==nCol1), (i==nCol2) ))
+ bFound = TRUE;
+
+ return bFound;
+}
+
+
+BOOL ScTable::HasAttribSelection( const ScMarkData& rMark, USHORT nMask ) const
+{
+ BOOL bFound=FALSE;
+ for (SCCOL i=0; i<=MAXCOL && !bFound; i++)
+ bFound |= aCol[i].HasAttribSelection( rMark, nMask );
+ return bFound;
+}
+
+
+BOOL ScTable::ExtendMerge( SCCOL nStartCol, SCROW nStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow,
+ BOOL bRefresh, BOOL bAttrs )
+{
+ if (!(ValidCol(nStartCol) && ValidCol(rEndCol)))
+ {
+ DBG_ERRORFILE("ScTable::ExtendMerge: invalid column number");
+ return FALSE;
+ }
+ BOOL bFound=FALSE;
+ SCCOL nOldEndX = rEndCol;
+ SCROW nOldEndY = rEndRow;
+ for (SCCOL i=nStartCol; i<=nOldEndX; i++)
+ bFound |= aCol[i].ExtendMerge( i, nStartRow, nOldEndY, rEndCol, rEndRow, bRefresh, bAttrs );
+ return bFound;
+}
+
+
+BOOL ScTable::IsBlockEmpty( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bIgnoreNotes ) const
+{
+ if (!(ValidCol(nCol1) && ValidCol(nCol2)))
+ {
+ DBG_ERRORFILE("ScTable::IsBlockEmpty: invalid column number");
+ return FALSE;
+ }
+ BOOL bEmpty = TRUE;
+ for (SCCOL i=nCol1; i<=nCol2 && bEmpty; i++)
+ bEmpty = aCol[i].IsEmptyBlock( nRow1, nRow2, bIgnoreNotes );
+ return bEmpty;
+}
+
+SCSIZE ScTable::FillMaxRot( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2,
+ SCCOL nCol, SCROW nAttrRow1, SCROW nAttrRow2, SCSIZE nArrY,
+ const ScPatternAttr* pPattern, const SfxItemSet* pCondSet ) const
+{
+ // Rueckgabe = neues nArrY
+
+ BYTE nRotDir = pPattern->GetRotateDir( pCondSet );
+ if ( nRotDir != SC_ROTDIR_NONE )
+ {
+ BOOL bHit = TRUE;
+ if ( nCol+1 < nX1 ) // column to the left
+ bHit = ( nRotDir != SC_ROTDIR_LEFT );
+ else if ( nCol > nX2+1 ) // column to the right
+ bHit = ( nRotDir != SC_ROTDIR_RIGHT ); // SC_ROTDIR_STANDARD may now also be extended to the left
+
+ if ( bHit )
+ {
+ double nFactor = 0.0;
+ if ( nCol > nX2+1 )
+ {
+ long nRotVal = ((const SfxInt32Item&) pPattern->
+ GetItem( ATTR_ROTATE_VALUE, pCondSet )).GetValue();
+ double nRealOrient = nRotVal * F_PI18000; // 1/100 Grad
+ double nCos = cos( nRealOrient );
+ double nSin = sin( nRealOrient );
+ //! begrenzen !!!
+ //! zusaetzlich Faktor fuer unterschiedliche PPT X/Y !!!
+
+ // bei SC_ROTDIR_LEFT kommt immer ein negativer Wert heraus,
+ // wenn der Modus beruecksichtigt wird
+ nFactor = -fabs( nCos / nSin );
+ }
+
+ for ( SCROW nRow = nAttrRow1; nRow <= nAttrRow2; nRow++ )
+ {
+ if ( !(pRowFlags->GetValue(nRow) & CR_HIDDEN) )
+ {
+ BOOL bHitOne = TRUE;
+ if ( nCol > nX2+1 )
+ {
+ // reicht die gedrehte Zelle bis in den sichtbaren Bereich?
+
+ SCCOL nTouchedCol = nCol;
+ long nWidth = (long) ( pRowHeight->GetValue(nRow) * nFactor );
+ DBG_ASSERT(nWidth <= 0, "Richtung falsch");
+ while ( nWidth < 0 && nTouchedCol > 0 )
+ {
+ --nTouchedCol;
+ nWidth += GetColWidth( nTouchedCol );
+ }
+ if ( nTouchedCol > nX2 )
+ bHitOne = FALSE;
+ }
+
+ if (bHitOne)
+ {
+ while ( nArrY<nArrCount && pRowInfo[nArrY].nRowNo < nRow )
+ ++nArrY;
+ if ( nArrY<nArrCount && pRowInfo[nArrY].nRowNo == nRow )
+ pRowInfo[nArrY].nRotMaxCol = nCol;
+ }
+ }
+ }
+ }
+ }
+
+ return nArrY;
+}
+
+void ScTable::FindMaxRotCol( RowInfo* pRowInfo, SCSIZE nArrCount, SCCOL nX1, SCCOL nX2 ) const
+{
+ if ( !pColWidth || !pRowHeight || !pColFlags || !pRowFlags )
+ {
+ DBG_ERROR( "Spalten-/Zeileninfo fehlt" );
+ return;
+ }
+
+ // nRotMaxCol ist auf SC_ROTMAX_NONE initialisiert, nRowNo ist schon gesetzt
+
+ SCROW nY1 = pRowInfo[0].nRowNo;
+ SCROW nY2 = pRowInfo[nArrCount-1].nRowNo;
+
+ for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
+ {
+ if ( !(pColFlags[nCol] & CR_HIDDEN) )
+ {
+ SCSIZE nArrY = 0;
+ ScDocAttrIterator aIter( pDocument, nTab, nCol, nY1, nCol, nY2 );
+ SCCOL nAttrCol;
+ SCROW nAttrRow1, nAttrRow2;
+ const ScPatternAttr* pPattern = aIter.GetNext( nAttrCol, nAttrRow1, nAttrRow2 );
+ while ( pPattern )
+ {
+ const SfxPoolItem* pCondItem;
+ if ( pPattern->GetItemSet().GetItemState( ATTR_CONDITIONAL, TRUE, &pCondItem )
+ == SFX_ITEM_SET )
+ {
+ // alle Formate durchgehen, damit die Zellen nicht einzeln
+ // angeschaut werden muessen
+
+ ULONG nIndex = ((const SfxUInt32Item*)pCondItem)->GetValue();
+ ScConditionalFormatList* pList = pDocument->GetCondFormList();
+ ScStyleSheetPool* pStylePool = pDocument->GetStyleSheetPool();
+ if (pList && pStylePool && nIndex)
+ {
+ const ScConditionalFormat* pFormat = pList->GetFormat(nIndex);
+ if ( pFormat )
+ {
+ USHORT nEntryCount = pFormat->Count();
+ for (USHORT nEntry=0; nEntry<nEntryCount; nEntry++)
+ {
+ String aStyleName = pFormat->GetEntry(nEntry)->GetStyle();
+ if (aStyleName.Len())
+ {
+ SfxStyleSheetBase* pStyleSheet =
+ pStylePool->Find( aStyleName, SFX_STYLE_FAMILY_PARA );
+ if ( pStyleSheet )
+ {
+ FillMaxRot( pRowInfo, nArrCount, nX1, nX2,
+ nCol, nAttrRow1, nAttrRow2,
+ nArrY, pPattern, &pStyleSheet->GetItemSet() );
+ // nArrY nicht veraendern
+ }
+ }
+ }
+ }
+ }
+ }
+
+ nArrY = FillMaxRot( pRowInfo, nArrCount, nX1, nX2,
+ nCol, nAttrRow1, nAttrRow2,
+ nArrY, pPattern, NULL );
+
+ pPattern = aIter.GetNext( nAttrCol, nAttrRow1, nAttrRow2 );
+ }
+ }
+ }
+}
+
+BOOL ScTable::HasBlockMatrixFragment( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) const
+{
+ // nix:0, mitte:1, unten:2, links:4, oben:8, rechts:16, offen:32
+ USHORT nEdges;
+
+ if ( nCol1 == nCol2 )
+ { // linke und rechte Spalte
+ const USHORT n = 4 | 16;
+ nEdges = aCol[nCol1].GetBlockMatrixEdges( nRow1, nRow2, n );
+ // nicht (4 und 16) oder 1 oder 32
+ if ( nEdges && (((nEdges & n) != n) || (nEdges & 33)) )
+ return TRUE; // linke oder rechte Kante fehlt oder offen
+ }
+ else
+ { // linke Spalte
+ nEdges = aCol[nCol1].GetBlockMatrixEdges( nRow1, nRow2, 4 );
+ // nicht 4 oder 1 oder 32
+ if ( nEdges && (((nEdges & 4) != 4) || (nEdges & 33)) )
+ return TRUE; // linke Kante fehlt oder offen
+ // rechte Spalte
+ nEdges = aCol[nCol2].GetBlockMatrixEdges( nRow1, nRow2, 16 );
+ // nicht 16 oder 1 oder 32
+ if ( nEdges && (((nEdges & 16) != 16) || (nEdges & 33)) )
+ return TRUE; // rechte Kante fehlt oder offen
+ }
+
+ if ( nRow1 == nRow2 )
+ { // obere und untere Zeile
+ BOOL bOpen = FALSE;
+ const USHORT n = 2 | 8;
+ for ( SCCOL i=nCol1; i<=nCol2; i++)
+ {
+ nEdges = aCol[i].GetBlockMatrixEdges( nRow1, nRow1, n );
+ if ( nEdges )
+ {
+ if ( (nEdges & n) != n )
+ return TRUE; // obere oder untere Kante fehlt
+ if ( nEdges & 4 )
+ bOpen = TRUE; // linke Kante oeffnet, weitersehen
+ else if ( !bOpen )
+ return TRUE; // es gibt was, was nicht geoeffnet wurde
+ if ( nEdges & 16 )
+ bOpen = FALSE; // rechte Kante schliesst
+ }
+ }
+ if ( bOpen )
+ return TRUE; // es geht noch weiter
+ }
+ else
+ {
+ USHORT j, n;
+ SCROW nR;
+ // erst obere Zeile, dann untere Zeile
+ for ( j=0, nR=nRow1, n=8; j<2; j++, nR=nRow2, n=2 )
+ {
+ BOOL bOpen = FALSE;
+ for ( SCCOL i=nCol1; i<=nCol2; i++)
+ {
+ nEdges = aCol[i].GetBlockMatrixEdges( nR, nR, n );
+ if ( nEdges )
+ {
+ // in oberere Zeile keine obere Kante bzw.
+ // in unterer Zeile keine untere Kante
+ if ( (nEdges & n) != n )
+ return TRUE;
+ if ( nEdges & 4 )
+ bOpen = TRUE; // linke Kante oeffnet, weitersehen
+ else if ( !bOpen )
+ return TRUE; // es gibt was, was nicht geoeffnet wurde
+ if ( nEdges & 16 )
+ bOpen = FALSE; // rechte Kante schliesst
+ }
+ }
+ if ( bOpen )
+ return TRUE; // es geht noch weiter
+ }
+ }
+ return FALSE;
+}
+
+
+BOOL ScTable::HasSelectionMatrixFragment( const ScMarkData& rMark ) const
+{
+ BOOL bFound=FALSE;
+ for (SCCOL i=0; i<=MAXCOL && !bFound; i++)
+ bFound |= aCol[i].HasSelectionMatrixFragment(rMark);
+ return bFound;
+}
+
+
+BOOL ScTable::IsBlockEditable( SCCOL nCol1, SCROW nRow1, SCCOL nCol2,
+ SCROW nRow2, BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
+{
+ if ( !ValidColRow( nCol2, nRow2 ) )
+ {
+ DBG_ERRORFILE("IsBlockEditable: invalid column or row");
+ if (pOnlyNotBecauseOfMatrix)
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ return FALSE;
+ }
+
+ BOOL bIsEditable = TRUE;
+ if ( nLockCount )
+ bIsEditable = FALSE;
+ else if ( bProtected && !pDocument->IsScenario(nTab) )
+ {
+ if((bIsEditable = !HasAttrib( nCol1, nRow1, nCol2, nRow2, HASATTR_PROTECTED )) != FALSE)
+ {
+ // If Sheet is protected and cells are not protected then
+ // check the active scenario protect flag if this range is
+ // on the active scenario range. Note the 'copy back' must also
+ // be set to apply protection.
+ USHORT nScenTab = nTab+1;
+ while(pDocument->IsScenario(nScenTab))
+ {
+ ScRange aEditRange(nCol1, nRow1, nScenTab, nCol2, nRow2, nScenTab);
+ if(pDocument->IsActiveScenario(nScenTab) && pDocument->HasScenarioRange(nScenTab, aEditRange))
+ {
+ USHORT nFlags;
+ pDocument->GetScenarioFlags(nScenTab,nFlags);
+ bIsEditable = !((nFlags & SC_SCENARIO_PROTECT) && (nFlags & SC_SCENARIO_TWOWAY));
+ break;
+ }
+ nScenTab++;
+ }
+ }
+ }
+ else if (pDocument->IsScenario(nTab))
+ {
+ // Determine if the preceding sheet is protected
+ SCTAB nActualTab = nTab;
+ do
+ {
+ nActualTab--;
+ }
+ while(pDocument->IsScenario(nActualTab));
+
+ if(pDocument->IsTabProtected(nActualTab))
+ {
+ ScRange aEditRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
+ if(pDocument->HasScenarioRange(nTab, aEditRange))
+ {
+ USHORT nFlags;
+ pDocument->GetScenarioFlags(nTab,nFlags);
+ bIsEditable = !(nFlags & SC_SCENARIO_PROTECT);
+ }
+ }
+ }
+ if ( bIsEditable )
+ {
+ if ( HasBlockMatrixFragment( nCol1, nRow1, nCol2, nRow2 ) )
+ {
+ bIsEditable = FALSE;
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = TRUE;
+ }
+ else if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ }
+ else if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ return bIsEditable;
+}
+
+
+BOOL ScTable::IsSelectionEditable( const ScMarkData& rMark,
+ BOOL* pOnlyNotBecauseOfMatrix /* = NULL */ ) const
+{
+ BOOL bIsEditable = TRUE;
+ if ( nLockCount )
+ bIsEditable = FALSE;
+ else if ( bProtected && !pDocument->IsScenario(nTab))
+ {
+ if((bIsEditable = !HasAttribSelection( rMark, HASATTR_PROTECTED )) != FALSE)
+ {
+ // If Sheet is protected and cells are not protected then
+ // check the active scenario protect flag if this area is
+ // in the active scenario range.
+ ScRangeList aRanges;
+ rMark.FillRangeListWithMarks( &aRanges, FALSE );
+ ULONG nRangeCount = aRanges.Count();
+ SCTAB nScenTab = nTab+1;
+ while(pDocument->IsScenario(nScenTab) && bIsEditable)
+ {
+ if(pDocument->IsActiveScenario(nScenTab))
+ {
+ for (ULONG i=0; i<nRangeCount && bIsEditable; i++)
+ {
+ ScRange aRange = *aRanges.GetObject(i);
+ if(pDocument->HasScenarioRange(nScenTab, aRange))
+ {
+ USHORT nFlags;
+ pDocument->GetScenarioFlags(nScenTab,nFlags);
+ bIsEditable = !((nFlags & SC_SCENARIO_PROTECT) && (nFlags & SC_SCENARIO_TWOWAY));
+ }
+ }
+ }
+ nScenTab++;
+ }
+ }
+ }
+ else if (pDocument->IsScenario(nTab))
+ {
+ // Determine if the preceding sheet is protected
+ SCTAB nActualTab = nTab;
+ do
+ {
+ nActualTab--;
+ }
+ while(pDocument->IsScenario(nActualTab));
+
+ if(pDocument->IsTabProtected(nActualTab))
+ {
+ ScRangeList aRanges;
+ rMark.FillRangeListWithMarks( &aRanges, FALSE );
+ ULONG nRangeCount = aRanges.Count();
+ for (ULONG i=0; i<nRangeCount && bIsEditable; i++)
+ {
+ ScRange aRange = *aRanges.GetObject(i);
+ if(pDocument->HasScenarioRange(nTab, aRange))
+ {
+ USHORT nFlags;
+ pDocument->GetScenarioFlags(nTab,nFlags);
+ bIsEditable = !(nFlags & SC_SCENARIO_PROTECT);
+ }
+ }
+ }
+ }
+ if ( bIsEditable )
+ {
+ if ( HasSelectionMatrixFragment( rMark ) )
+ {
+ bIsEditable = FALSE;
+ if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = TRUE;
+ }
+ else if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ }
+ else if ( pOnlyNotBecauseOfMatrix )
+ *pOnlyNotBecauseOfMatrix = FALSE;
+ return bIsEditable;
+}
+
+
+
+void ScTable::LockTable()
+{
+ ++nLockCount;
+}
+
+
+void ScTable::UnlockTable()
+{
+ if (nLockCount)
+ --nLockCount;
+ else
+ {
+ DBG_ERROR("UnlockTable ohne LockTable");
+ }
+}
+
+
+void ScTable::MergeSelectionPattern( ScMergePatternState& rState, const ScMarkData& rMark, BOOL bDeep ) const
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].MergeSelectionPattern( rState, rMark, bDeep );
+}
+
+
+void ScTable::MergePatternArea( ScMergePatternState& rState, SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2, BOOL bDeep ) const
+{
+ for (SCCOL i=nCol1; i<=nCol2; i++)
+ aCol[i].MergePatternArea( rState, nRow1, nRow2, bDeep );
+}
+
+
+void ScTable::MergeBlockFrame( SvxBoxItem* pLineOuter, SvxBoxInfoItem* pLineInner, ScLineFlags& rFlags,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow ) const
+{
+ if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
+ {
+ PutInOrder(nStartCol, nEndCol);
+ PutInOrder(nStartRow, nEndRow);
+ for (SCCOL i=nStartCol; i<=nEndCol; i++)
+ aCol[i].MergeBlockFrame( pLineOuter, pLineInner, rFlags,
+ nStartRow, nEndRow, (i==nStartCol), nEndCol-i );
+ }
+}
+
+
+void ScTable::ApplyBlockFrame( const SvxBoxItem* pLineOuter, const SvxBoxInfoItem* pLineInner,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
+{
+ if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
+ {
+ PutInOrder(nStartCol, nEndCol);
+ PutInOrder(nStartRow, nEndRow);
+ for (SCCOL i=nStartCol; i<=nEndCol; i++)
+ aCol[i].ApplyBlockFrame( pLineOuter, pLineInner,
+ nStartRow, nEndRow, (i==nStartCol), nEndCol-i );
+ }
+}
+
+
+void ScTable::ApplyPattern( SCCOL nCol, SCROW nRow, const ScPatternAttr& rAttr )
+{
+ if (ValidColRow(nCol,nRow))
+ aCol[nCol].ApplyPattern( nRow, rAttr );
+}
+
+
+void ScTable::ApplyPatternArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ const ScPatternAttr& rAttr )
+{
+ if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
+ {
+ PutInOrder(nStartCol, nEndCol);
+ PutInOrder(nStartRow, nEndRow);
+ for (SCCOL i = nStartCol; i <= nEndCol; i++)
+ aCol[i].ApplyPatternArea(nStartRow, nEndRow, rAttr);
+ }
+}
+
+void ScTable::ApplyPatternIfNumberformatIncompatible( const ScRange& rRange,
+ const ScPatternAttr& rPattern, short nNewType )
+{
+ SCCOL nEndCol = rRange.aEnd.Col();
+ for ( SCCOL nCol = rRange.aStart.Col(); nCol <= nEndCol; nCol++ )
+ {
+ aCol[nCol].ApplyPatternIfNumberformatIncompatible( rRange, rPattern, nNewType );
+ }
+}
+
+
+
+void ScTable::ApplyStyle( SCCOL nCol, SCROW nRow, const ScStyleSheet& rStyle )
+{
+ if (ValidColRow(nCol,nRow))
+ aCol[nCol].ApplyStyle( nRow, rStyle );
+}
+
+
+void ScTable::ApplyStyleArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, const ScStyleSheet& rStyle )
+{
+ if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
+ {
+ PutInOrder(nStartCol, nEndCol);
+ PutInOrder(nStartRow, nEndRow);
+ for (SCCOL i = nStartCol; i <= nEndCol; i++)
+ aCol[i].ApplyStyleArea(nStartRow, nEndRow, rStyle);
+ }
+}
+
+
+void ScTable::ApplySelectionStyle(const ScStyleSheet& rStyle, const ScMarkData& rMark)
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].ApplySelectionStyle( rStyle, rMark );
+}
+
+
+void ScTable::ApplySelectionLineStyle( const ScMarkData& rMark,
+ const SvxBorderLine* pLine, BOOL bColorOnly )
+{
+ if ( bColorOnly && !pLine )
+ return;
+
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].ApplySelectionLineStyle( rMark, pLine, bColorOnly );
+}
+
+
+const ScStyleSheet* ScTable::GetStyle( SCCOL nCol, SCROW nRow ) const
+{
+ if (ValidColRow(nCol, nRow))
+ return aCol[nCol].GetStyle(nRow);
+ else
+ return NULL;
+}
+
+
+const ScStyleSheet* ScTable::GetSelectionStyle( const ScMarkData& rMark, BOOL& rFound ) const
+{
+ rFound = FALSE;
+
+ BOOL bEqual = TRUE;
+ BOOL bColFound;
+
+ const ScStyleSheet* pStyle = NULL;
+ const ScStyleSheet* pNewStyle;
+
+ for (SCCOL i=0; i<=MAXCOL && bEqual; i++)
+ if (rMark.HasMultiMarks(i))
+ {
+ pNewStyle = aCol[i].GetSelectionStyle( rMark, bColFound );
+ if (bColFound)
+ {
+ rFound = TRUE;
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = FALSE; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+
+const ScStyleSheet* ScTable::GetAreaStyle( BOOL& rFound, SCCOL nCol1, SCROW nRow1,
+ SCCOL nCol2, SCROW nRow2 ) const
+{
+ rFound = FALSE;
+
+ BOOL bEqual = TRUE;
+ BOOL bColFound;
+
+ const ScStyleSheet* pStyle = NULL;
+ const ScStyleSheet* pNewStyle;
+
+ for (SCCOL i=nCol1; i<=nCol2 && bEqual; i++)
+ {
+ pNewStyle = aCol[i].GetAreaStyle(bColFound, nRow1, nRow2);
+ if (bColFound)
+ {
+ rFound = TRUE;
+ if ( !pNewStyle || ( pStyle && pNewStyle != pStyle ) )
+ bEqual = FALSE; // unterschiedliche
+ pStyle = pNewStyle;
+ }
+ }
+
+ return bEqual ? pStyle : NULL;
+}
+
+
+BOOL ScTable::IsStyleSheetUsed( const ScStyleSheet& rStyle, BOOL bGatherAllStyles ) const
+{
+ BOOL bIsUsed = FALSE;
+
+ for ( SCCOL i=0; i<=MAXCOL; i++ )
+ {
+ if ( aCol[i].IsStyleSheetUsed( rStyle, bGatherAllStyles ) )
+ {
+ if ( !bGatherAllStyles )
+ return TRUE;
+ bIsUsed = TRUE;
+ }
+ }
+
+ return bIsUsed;
+}
+
+
+void ScTable::StyleSheetChanged( const SfxStyleSheetBase* pStyleSheet, BOOL bRemoved,
+ OutputDevice* pDev,
+ double nPPTX, double nPPTY,
+ const Fraction& rZoomX, const Fraction& rZoomY )
+{
+ BOOL* pUsed = new BOOL[MAXROWCOUNT];
+ memset( pUsed, 0, sizeof(BOOL) * (MAXROWCOUNT) );
+
+ SCCOL nCol;
+ for (nCol=0; nCol<=MAXCOL; nCol++)
+ aCol[nCol].FindStyleSheet( pStyleSheet, pUsed, bRemoved );
+
+ BOOL bFound = FALSE;
+ SCROW nStart = 0, nEnd = 0;
+ for (SCROW i=0; i<=MAXROW; i++)
+ {
+ if (pUsed[i])
+ {
+ if (!bFound)
+ {
+ nStart = i;
+ bFound = TRUE;
+ }
+ nEnd = i;
+ }
+ else if (bFound)
+ {
+ SetOptimalHeight( nStart, nEnd, 0, pDev, nPPTX, nPPTY, rZoomX, rZoomY, FALSE );
+ bFound = FALSE;
+ }
+ }
+ if (bFound)
+ SetOptimalHeight( nStart, nEnd, 0, pDev, nPPTX, nPPTY, rZoomX, rZoomY, FALSE );
+
+ delete[] pUsed;
+}
+
+
+BOOL ScTable::ApplyFlags( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ INT16 nFlags )
+{
+ BOOL bChanged = FALSE;
+ if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
+ for (SCCOL i = nStartCol; i <= nEndCol; i++)
+ bChanged |= aCol[i].ApplyFlags(nStartRow, nEndRow, nFlags);
+ return bChanged;
+}
+
+
+BOOL ScTable::RemoveFlags( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ INT16 nFlags )
+{
+ BOOL bChanged = FALSE;
+ if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
+ for (SCCOL i = nStartCol; i <= nEndCol; i++)
+ bChanged |= aCol[i].RemoveFlags(nStartRow, nEndRow, nFlags);
+ return bChanged;
+}
+
+
+void ScTable::SetPattern( SCCOL nCol, SCROW nRow, const ScPatternAttr& rAttr, BOOL bPutToPool )
+{
+ if (ValidColRow(nCol,nRow))
+ aCol[nCol].SetPattern( nRow, rAttr, bPutToPool );
+}
+
+
+void ScTable::ApplyAttr( SCCOL nCol, SCROW nRow, const SfxPoolItem& rAttr )
+{
+ if (ValidColRow(nCol,nRow))
+ aCol[nCol].ApplyAttr( nRow, rAttr );
+}
+
+
+void ScTable::ApplySelectionCache( SfxItemPoolCache* pCache, const ScMarkData& rMark )
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].ApplySelectionCache( pCache, rMark );
+}
+
+
+void ScTable::ChangeSelectionIndent( BOOL bIncrement, const ScMarkData& rMark )
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].ChangeSelectionIndent( bIncrement, rMark );
+}
+
+
+void ScTable::ClearSelectionItems( const USHORT* pWhich, const ScMarkData& rMark )
+{
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ aCol[i].ClearSelectionItems( pWhich, rMark );
+}
+
+
+// Spaltenbreiten / Zeilenhoehen
+
+void ScTable::SetColWidth( SCCOL nCol, USHORT nNewWidth )
+{
+ if (VALIDCOL(nCol) && pColWidth)
+ {
+ if (!nNewWidth)
+ {
+// DBG_ERROR("Spaltenbreite 0 in SetColWidth");
+ nNewWidth = STD_COL_WIDTH;
+ }
+
+ if ( nNewWidth != pColWidth[nCol] )
+ {
+ nRecalcLvl++;
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ pDrawLayer->WidthChanged( nTab, nCol, ((long) nNewWidth) - (long) pColWidth[nCol] );
+ pColWidth[nCol] = nNewWidth;
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+ }
+ }
+ else
+ {
+ DBG_ERROR("Falsche Spaltennummer oder keine Breiten");
+ }
+}
+
+
+void ScTable::SetRowHeight( SCROW nRow, USHORT nNewHeight )
+{
+ if (VALIDROW(nRow) && pRowHeight)
+ {
+ if (!nNewHeight)
+ {
+ DBG_ERROR("Zeilenhoehe 0 in SetRowHeight");
+ nNewHeight = ScGlobal::nStdRowHeight;
+ }
+
+ USHORT nOldHeight = pRowHeight->GetValue(nRow);
+ if ( nNewHeight != nOldHeight )
+ {
+ nRecalcLvl++;
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ pDrawLayer->HeightChanged( nTab, nRow, ((long) nNewHeight) - (long) nOldHeight );
+ pRowHeight->SetValue( nRow, nNewHeight);
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+ }
+ }
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Hoehen");
+ }
+}
+
+
+BOOL ScTable::SetRowHeightRange( SCROW nStartRow, SCROW nEndRow, USHORT nNewHeight,
+ double /* nPPTX */, double nPPTY )
+{
+ BOOL bChanged = FALSE;
+ if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowHeight)
+ {
+ nRecalcLvl++;
+ if (!nNewHeight)
+ {
+ DBG_ERROR("Zeilenhoehe 0 in SetRowHeight");
+ nNewHeight = ScGlobal::nStdRowHeight;
+ }
+
+ long nNewPix = (long) ( nNewHeight * nPPTY );
+
+ BOOL bSingle = FALSE; // TRUE = process every row for its own
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ if (pDrawLayer->HasObjectsInRows( nTab, nStartRow, nEndRow ))
+ bSingle = TRUE;
+
+ if (bSingle)
+ {
+ size_t nIndex;
+ SCROW nRegionEndRow;
+ USHORT nOldHeight = pRowHeight->GetValue( nStartRow, nIndex, nRegionEndRow);
+ if (nNewHeight == nOldHeight && nEndRow <= nRegionEndRow)
+ bSingle = FALSE; // no difference in this range
+ }
+ if (bSingle)
+ {
+ if (nEndRow-nStartRow < 20)
+ {
+ // Whether new pixel size will differ from old pixel size in any row.
+ ScCompressedArrayIterator< SCROW, USHORT> aIter( *pRowHeight,
+ nStartRow, nEndRow);
+ do
+ {
+ if (*aIter != nNewHeight)
+ bChanged = (nNewPix != (long) (*aIter * nPPTY));
+ } while (!bChanged && aIter.NextRange());
+
+ /* #i94028# #i94991# If drawing objects are involved, each row
+ has to be changed for its own, because each call to
+ ScDrawLayer::HeightChanged expects correct row heights
+ above passed row in the document. Cannot use array iterator
+ because array changes in every cycle. */
+ if( pDrawLayer )
+ {
+ for( SCROW nRow = nStartRow; nRow <= nEndRow ; ++nRow )
+ {
+ pDrawLayer->HeightChanged( nTab, nRow,
+ ((long) nNewHeight) - ((long) pRowHeight->GetValue( nRow )));
+ pRowHeight->SetValue( nRow, nNewHeight );
+ }
+ }
+ else
+ pRowHeight->SetValue( nStartRow, nEndRow, nNewHeight);
+ }
+ else
+ {
+ SCROW nMid = (nStartRow+nEndRow) / 2;
+ if (SetRowHeightRange( nStartRow, nMid, nNewHeight, 1.0, 1.0 ))
+ bChanged = TRUE;
+ if (SetRowHeightRange( nMid+1, nEndRow, nNewHeight, 1.0, 1.0 ))
+ bChanged = TRUE;
+ }
+ }
+ else
+ {
+ if (pDrawLayer)
+ {
+ unsigned long nOldHeights = pRowHeight->SumValues( nStartRow, nEndRow);
+ // FIXME: should we test for overflows?
+ long nHeightDif = (long) (unsigned long) nNewHeight *
+ (nEndRow - nStartRow + 1) - nOldHeights;
+ pDrawLayer->HeightChanged( nTab, nEndRow, nHeightDif );
+ }
+ // Whether new pixel size will differ from old pixel size in any row.
+ ScCompressedArrayIterator< SCROW, USHORT> aIter( *pRowHeight,
+ nStartRow, nEndRow);
+ do
+ {
+ if (*aIter != nNewHeight)
+ bChanged = (nNewPix != (long) (*aIter * nPPTY));
+ } while (!bChanged && aIter.NextRange());
+ pRowHeight->SetValue( nStartRow, nEndRow, nNewHeight);
+ }
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+ }
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Hoehen");
+ }
+
+ return bChanged;
+}
+
+
+void ScTable::SetManualHeight( SCROW nStartRow, SCROW nEndRow, BOOL bManual )
+{
+ if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowFlags)
+ {
+ if (bManual)
+ pRowFlags->OrValue( nStartRow, nEndRow, CR_MANUALSIZE);
+ else
+ pRowFlags->AndValue( nStartRow, nEndRow, sal::static_int_cast<BYTE>(~CR_MANUALSIZE));
+ }
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Zeilenflags");
+ }
+}
+
+
+USHORT ScTable::GetColWidth( SCCOL nCol ) const
+{
+ DBG_ASSERT(VALIDCOL(nCol),"Falsche Spaltennummer");
+
+ if (VALIDCOL(nCol) && pColFlags && pColWidth)
+ {
+ if ( pColFlags[nCol] & CR_HIDDEN )
+ return 0;
+ else
+ return pColWidth[nCol];
+ }
+ else
+ return (USHORT) STD_COL_WIDTH;
+}
+
+
+USHORT ScTable::GetOriginalWidth( SCCOL nCol ) const // immer die eingestellte
+{
+ DBG_ASSERT(VALIDCOL(nCol),"Falsche Spaltennummer");
+
+ if (VALIDCOL(nCol) && pColWidth)
+ return pColWidth[nCol];
+ else
+ return (USHORT) STD_COL_WIDTH;
+}
+
+
+USHORT ScTable::GetCommonWidth( SCCOL nEndCol ) const
+{
+ // get the width that is used in the largest continuous column range (up to nEndCol)
+
+ if ( !ValidCol(nEndCol) )
+ {
+ DBG_ERROR("wrong column");
+ nEndCol = MAXCOL;
+ }
+
+ USHORT nMaxWidth = 0;
+ USHORT nMaxCount = 0;
+ USHORT nRangeStart = 0;
+ while ( nRangeStart <= nEndCol )
+ {
+ // skip hidden columns
+ while ( nRangeStart <= nEndCol && (pColFlags[nRangeStart] & CR_HIDDEN) )
+ ++nRangeStart;
+ if ( nRangeStart <= nEndCol )
+ {
+ USHORT nThisCount = 0;
+ USHORT nThisWidth = pColWidth[nRangeStart];
+ USHORT nRangeEnd = nRangeStart;
+ while ( nRangeEnd <= nEndCol && pColWidth[nRangeEnd] == nThisWidth )
+ {
+ ++nThisCount;
+ ++nRangeEnd;
+
+ // skip hidden columns
+ while ( nRangeEnd <= nEndCol && (pColFlags[nRangeEnd] & CR_HIDDEN) )
+ ++nRangeEnd;
+ }
+
+ if ( nThisCount > nMaxCount )
+ {
+ nMaxCount = nThisCount;
+ nMaxWidth = nThisWidth;
+ }
+
+ nRangeStart = nRangeEnd; // next range
+ }
+ }
+
+ return nMaxWidth;
+}
+
+
+USHORT ScTable::GetRowHeight( SCROW nRow ) const
+{
+ DBG_ASSERT(VALIDROW(nRow),"Falsche Zeilennummer");
+
+ if (VALIDROW(nRow) && pRowFlags && pRowHeight)
+ {
+ if ( pRowFlags->GetValue(nRow) & CR_HIDDEN )
+ return 0;
+ else
+ return pRowHeight->GetValue(nRow);
+ }
+ else
+ return (USHORT) ScGlobal::nStdRowHeight;
+}
+
+
+ULONG ScTable::GetRowHeight( SCROW nStartRow, SCROW nEndRow ) const
+{
+ DBG_ASSERT(VALIDROW(nStartRow) && VALIDROW(nEndRow),"Falsche Zeilennummer");
+
+ if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowFlags && pRowHeight)
+ {
+ return pRowFlags->SumCoupledArrayForCondition( nStartRow, nEndRow,
+ CR_HIDDEN, 0, *pRowHeight);
+ }
+ else
+ return (ULONG) ((nEndRow - nStartRow + 1) * ScGlobal::nStdRowHeight);
+}
+
+
+ULONG ScTable::GetScaledRowHeight( SCROW nStartRow, SCROW nEndRow, double fScale ) const
+{
+ DBG_ASSERT(VALIDROW(nStartRow) && VALIDROW(nEndRow),"Falsche Zeilennummer");
+
+ if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowFlags && pRowHeight)
+ {
+ return pRowFlags->SumScaledCoupledArrayForCondition( nStartRow,
+ nEndRow, CR_HIDDEN, 0, *pRowHeight, fScale);
+ }
+ else
+ return (ULONG) ((nEndRow - nStartRow + 1) * ScGlobal::nStdRowHeight * fScale);
+}
+
+
+USHORT ScTable::GetOriginalHeight( SCROW nRow ) const // non-0 even if hidden
+{
+ DBG_ASSERT(VALIDROW(nRow),"wrong row number");
+
+ if (VALIDROW(nRow) && pRowHeight)
+ return pRowHeight->GetValue(nRow);
+ else
+ return (USHORT) ScGlobal::nStdRowHeight;
+}
+
+
+// Spalten-/Zeilen-Flags
+
+
+SCROW ScTable::GetHiddenRowCount( SCROW nRow ) const
+{
+ SCROW nEndRow = nRow;
+ if ( pRowFlags )
+ {
+ nEndRow = pRowFlags->GetBitStateEnd( nRow, CR_HIDDEN, CR_HIDDEN);
+ if (ValidRow(nEndRow))
+ ++nEndRow;
+ else
+ nEndRow = nRow;
+ }
+ return nEndRow - nRow;
+}
+
+
+//! ShowRows / DBShowRows zusammenfassen
+
+void ScTable::ShowCol(SCCOL nCol, BOOL bShow)
+{
+ if (VALIDCOL(nCol) && pColFlags)
+ {
+ BOOL bWasVis = ( pColFlags[nCol] & CR_HIDDEN ) == 0;
+ if (bWasVis != bShow)
+ {
+ nRecalcLvl++;
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ if (bShow)
+ pDrawLayer->WidthChanged( nTab, nCol, (long) pColWidth[nCol] );
+ else
+ pDrawLayer->WidthChanged( nTab, nCol, -(long) pColWidth[nCol] );
+ }
+
+ if (bShow)
+ pColFlags[nCol] &= ~CR_HIDDEN;
+ else
+ pColFlags[nCol] |= CR_HIDDEN;
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+
+ ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
+ if ( pCharts && pCharts->GetCount() )
+ pCharts->SetRangeDirty(ScRange( nCol, 0, nTab, nCol, MAXROW, nTab ));
+ }
+ }
+ else
+ {
+ DBG_ERROR("Falsche Spaltennummer oder keine Flags");
+ }
+}
+
+
+void ScTable::ShowRow(SCROW nRow, BOOL bShow)
+{
+ if (VALIDROW(nRow) && pRowFlags)
+ {
+ BYTE nFlags = pRowFlags->GetValue(nRow);
+ BOOL bWasVis = ( nFlags & CR_HIDDEN ) == 0;
+ if (bWasVis != bShow)
+ {
+ nRecalcLvl++;
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ if (bShow)
+ pDrawLayer->HeightChanged( nTab, nRow, (long) pRowHeight->GetValue(nRow) );
+ else
+ pDrawLayer->HeightChanged( nTab, nRow, -(long) pRowHeight->GetValue(nRow) );
+ }
+
+ if (bShow)
+ pRowFlags->SetValue( nRow, nFlags & ~(CR_HIDDEN | CR_FILTERED));
+ else
+ pRowFlags->SetValue( nRow, nFlags | CR_HIDDEN);
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+
+ ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
+ if ( pCharts && pCharts->GetCount() )
+ pCharts->SetRangeDirty(ScRange( 0, nRow, nTab, MAXCOL, nRow, nTab ));
+ }
+ }
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Flags");
+ }
+}
+
+
+void ScTable::DBShowRow(SCROW nRow, BOOL bShow)
+{
+ if (VALIDROW(nRow) && pRowFlags)
+ {
+ BYTE nFlags = pRowFlags->GetValue(nRow);
+ BOOL bWasVis = ( nFlags & CR_HIDDEN ) == 0;
+ nRecalcLvl++;
+ if (bWasVis != bShow)
+ {
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ if (bShow)
+ pDrawLayer->HeightChanged( nTab, nRow, (long) pRowHeight->GetValue(nRow) );
+ else
+ pDrawLayer->HeightChanged( nTab, nRow, -(long) pRowHeight->GetValue(nRow) );
+ }
+ }
+
+ // Filter-Flag immer setzen, auch wenn Hidden unveraendert
+ if (bShow)
+ pRowFlags->SetValue( nRow, nFlags & ~(CR_HIDDEN | CR_FILTERED));
+ else
+ pRowFlags->SetValue( nRow, nFlags | (CR_HIDDEN | CR_FILTERED));
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+
+ if (bWasVis != bShow)
+ {
+ ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
+ if ( pCharts && pCharts->GetCount() )
+ pCharts->SetRangeDirty(ScRange( 0, nRow, nTab, MAXCOL, nRow, nTab ));
+
+ if (pOutlineTable)
+ UpdateOutlineRow( nRow, nRow, bShow );
+ }
+ }
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Flags");
+ }
+}
+
+
+void ScTable::DBShowRows(SCROW nRow1, SCROW nRow2, BOOL bShow)
+{
+ SCROW nStartRow = nRow1;
+ nRecalcLvl++;
+ while (nStartRow <= nRow2)
+ {
+ BYTE nOldFlag = pRowFlags->GetValue(nStartRow) & CR_HIDDEN;
+ SCROW nEndRow = pRowFlags->GetBitStateEnd( nStartRow, CR_HIDDEN, nOldFlag);
+ if (nEndRow > nRow2)
+ nEndRow = nRow2;
+
+ BOOL bWasVis = ( nOldFlag == 0 );
+ BOOL bChanged = ( bWasVis != bShow );
+ if ( bChanged )
+ {
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ long nHeight = (long) pRowHeight->SumValues( nStartRow, nEndRow);
+ if (bShow)
+ pDrawLayer->HeightChanged( nTab, nStartRow, nHeight );
+ else
+ pDrawLayer->HeightChanged( nTab, nStartRow, -nHeight );
+ }
+ }
+
+ if (bShow)
+ pRowFlags->AndValue( nStartRow, nEndRow, sal::static_int_cast<BYTE>(~(CR_HIDDEN | CR_FILTERED)) );
+ else
+ pRowFlags->OrValue( nStartRow, nEndRow, (CR_HIDDEN | CR_FILTERED));
+
+ if ( bChanged )
+ {
+ ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
+ if ( pCharts && pCharts->GetCount() )
+ pCharts->SetRangeDirty(ScRange( 0, nStartRow, nTab, MAXCOL, nEndRow, nTab ));
+ }
+
+ nStartRow = nEndRow + 1;
+ }
+
+ // #i12341# For Show/Hide rows, the outlines are updated separately from the outside.
+ // For filtering, the changes aren't visible to the caller, so UpdateOutlineRow has
+ // to be done here.
+ if (pOutlineTable)
+ UpdateOutlineRow( nRow1, nRow2, bShow );
+
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+}
+
+
+void ScTable::ShowRows(SCROW nRow1, SCROW nRow2, BOOL bShow)
+{
+ SCROW nStartRow = nRow1;
+ nRecalcLvl++;
+ while (nStartRow <= nRow2)
+ {
+ BYTE nOldFlag = pRowFlags->GetValue(nStartRow) & CR_HIDDEN;
+ SCROW nEndRow = pRowFlags->GetBitStateEnd( nStartRow, CR_HIDDEN, nOldFlag);
+ if (nEndRow > nRow2)
+ nEndRow = nRow2;
+
+ BOOL bWasVis = ( nOldFlag == 0 );
+ BOOL bChanged = ( bWasVis != bShow );
+ if ( bChanged )
+ {
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ long nHeight = (long) pRowHeight->SumValues( nStartRow, nEndRow);
+ if (bShow)
+ pDrawLayer->HeightChanged( nTab, nStartRow, nHeight );
+ else
+ pDrawLayer->HeightChanged( nTab, nStartRow, -nHeight );
+ }
+ }
+
+ if (bShow)
+ pRowFlags->AndValue( nStartRow, nEndRow, sal::static_int_cast<BYTE>(~(CR_HIDDEN | CR_FILTERED)) );
+ else
+ pRowFlags->OrValue( nStartRow, nEndRow, CR_HIDDEN);
+
+ if ( bChanged )
+ {
+ ScChartListenerCollection* pCharts = pDocument->GetChartListenerCollection();
+ if ( pCharts && pCharts->GetCount() )
+ pCharts->SetRangeDirty(ScRange( 0, nStartRow, nTab, MAXCOL, nEndRow, nTab ));
+ }
+
+ nStartRow = nEndRow + 1;
+ }
+ if( !--nRecalcLvl )
+ SetDrawPageSize();
+}
+
+
+BOOL ScTable::IsFiltered(SCROW nRow) const
+{
+ if (VALIDROW(nRow) && pRowFlags)
+ return ( pRowFlags->GetValue(nRow) & CR_FILTERED ) != 0;
+
+ DBG_ERROR("Falsche Zeilennummer oder keine Flags");
+ return FALSE;
+}
+
+
+void ScTable::SetColFlags( SCCOL nCol, BYTE nNewFlags )
+{
+ if (VALIDCOL(nCol) && pColFlags)
+ pColFlags[nCol] = nNewFlags;
+ else
+ {
+ DBG_ERROR("Falsche Spaltennummer oder keine Flags");
+ }
+}
+
+
+void ScTable::SetRowFlags( SCROW nRow, BYTE nNewFlags )
+{
+ if (VALIDROW(nRow) && pRowFlags)
+ pRowFlags->SetValue( nRow, nNewFlags);
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer oder keine Flags");
+ }
+}
+
+
+void ScTable::SetRowFlags( SCROW nStartRow, SCROW nEndRow, BYTE nNewFlags )
+{
+ if (VALIDROW(nStartRow) && VALIDROW(nEndRow) && pRowFlags)
+ pRowFlags->SetValue( nStartRow, nEndRow, nNewFlags);
+ else
+ {
+ DBG_ERROR("Falsche Zeilennummer(n) oder keine Flags");
+ }
+}
+
+
+BYTE ScTable::GetColFlags( SCCOL nCol ) const
+{
+ if (VALIDCOL(nCol) && pColFlags)
+ return pColFlags[nCol];
+ else
+ return 0;
+}
+
+
+BYTE ScTable::GetRowFlags( SCROW nRow ) const
+{
+ if (VALIDROW(nRow) && pRowFlags)
+ return pRowFlags->GetValue(nRow);
+ else
+ return 0;
+}
+
+
+SCROW ScTable::GetLastFlaggedRow() const
+{
+ if ( !pRowFlags )
+ return 0;
+
+ SCROW nLastFound = pRowFlags->GetLastAnyBitAccess( 0, sal::static_int_cast<BYTE>(~CR_PAGEBREAK) );
+ return ValidRow(nLastFound) ? nLastFound : 0;
+}
+
+
+SCCOL ScTable::GetLastChangedCol() const
+{
+ if ( !pColFlags )
+ return 0;
+
+ SCCOL nLastFound = 0;
+ for (SCCOL nCol = 1; nCol <= MAXCOL; nCol++)
+ if ((pColFlags[nCol] & ~CR_PAGEBREAK) || (pColWidth[nCol] != STD_COL_WIDTH))
+ nLastFound = nCol;
+
+ return nLastFound;
+}
+
+
+SCROW ScTable::GetLastChangedRow() const
+{
+ if ( !pRowFlags )
+ return 0;
+
+ SCROW nLastFlags = pRowFlags->GetLastAnyBitAccess( 0, sal::static_int_cast<BYTE>(~CR_PAGEBREAK) );
+ if (!ValidRow(nLastFlags))
+ nLastFlags = 0;
+
+ SCROW nLastHeight = pRowHeight->GetLastUnequalAccess( 0, ScGlobal::nStdRowHeight);
+ if (!ValidRow(nLastHeight))
+ nLastHeight = 0;
+
+ return std::max( nLastFlags, nLastHeight);
+}
+
+
+BOOL ScTable::UpdateOutlineCol( SCCOL nStartCol, SCCOL nEndCol, BOOL bShow )
+{
+ if (pOutlineTable && pColFlags)
+ {
+ ScBitMaskCompressedArray< SCCOLROW, BYTE> aArray( MAXCOL, pColFlags, MAXCOLCOUNT);
+ return pOutlineTable->GetColArray()->ManualAction( nStartCol, nEndCol, bShow, aArray );
+ }
+ else
+ return FALSE;
+}
+
+
+BOOL ScTable::UpdateOutlineRow( SCROW nStartRow, SCROW nEndRow, BOOL bShow )
+{
+ if (pOutlineTable && pRowFlags)
+ return pOutlineTable->GetRowArray()->ManualAction( nStartRow, nEndRow, bShow, *pRowFlags );
+ else
+ return FALSE;
+}
+
+
+void ScTable::ExtendHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 )
+{
+ if (pColFlags)
+ {
+ while ( rX1>0 ? (pColFlags[rX1-1] & CR_HIDDEN) : FALSE )
+ --rX1;
+ while ( rX2<MAXCOL ? (pColFlags[rX2+1] & CR_HIDDEN) : FALSE )
+ ++rX2;
+ }
+ if (pRowFlags)
+ {
+ if (rY1 > 0)
+ {
+ SCROW nStartRow = pRowFlags->GetBitStateStart( rY1-1, CR_HIDDEN, CR_HIDDEN);
+ if (ValidRow(nStartRow))
+ rY1 = nStartRow;
+ }
+ if (rY2 < MAXROW)
+ {
+ SCROW nEndRow = pRowFlags->GetBitStateEnd( rY2+1, CR_HIDDEN, CR_HIDDEN);
+ if (ValidRow(nEndRow))
+ rY2 = nEndRow;
+ }
+ }
+}
+
+
+void ScTable::StripHidden( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 )
+{
+ if (pColFlags)
+ {
+ while ( rX2>rX1 && (pColFlags[rX2] & CR_HIDDEN) )
+ --rX2;
+ while ( rX2>rX1 && (pColFlags[rX1] & CR_HIDDEN) )
+ ++rX1;
+ }
+ if (pRowFlags)
+ {
+ if (rY1 < rY2)
+ {
+ SCROW nStartRow = pRowFlags->GetBitStateStart( rY2, CR_HIDDEN, CR_HIDDEN);
+ if (ValidRow(nStartRow) && nStartRow >= rY1)
+ rY2 = nStartRow;
+ }
+ if (rY1 < rY2)
+ {
+ SCROW nEndRow = pRowFlags->GetBitStateEnd( rY1, CR_HIDDEN, CR_HIDDEN);
+ if (ValidRow(nEndRow) && nEndRow <= rY2)
+ rY1 = nEndRow;
+ }
+ }
+}
+
+
+// Auto-Outline
+
+template< typename T >
+short DiffSign( T a, T b )
+{
+ return (a<b) ? -1 :
+ (a>b) ? 1 : 0;
+}
+
+
+void ScTable::DoAutoOutline( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
+{
+ BOOL bSizeChanged = FALSE;
+ BOOL bMissed = FALSE;
+
+ SCCOL nCol;
+ SCROW nRow;
+ SCROW i;
+ BOOL bFound;
+ ScOutlineArray* pArray;
+ ScBaseCell* pCell;
+ ScRange aRef;
+/* ScPatternAttr aBoldPattern( pDocument->GetPool() ); //! spezielle Format-Vorlage
+ aBoldPattern.GetItemSet().Put( SvxWeightItem( WEIGHT_BOLD ) );
+*/
+
+ StartOutlineTable();
+
+ // Zeilen
+
+ SCROW nCount = nEndRow-nStartRow+1;
+ BOOL* pUsed = new BOOL[nCount];
+ for (i=0; i<nCount; i++)
+ pUsed[i] = FALSE;
+ for (nCol=nStartCol; nCol<=nEndCol; nCol++)
+ if (!aCol[nCol].IsEmptyData())
+ aCol[nCol].FindUsed( nStartRow, nEndRow, pUsed );
+
+ pArray = pOutlineTable->GetRowArray();
+ for (nRow=nStartRow; nRow<=nEndRow; nRow++)
+ if (pUsed[nRow-nStartRow])
+ {
+ bFound = FALSE;
+ for (nCol=nStartCol; nCol<=nEndCol && !bFound; nCol++)
+ if (!aCol[nCol].IsEmptyData())
+ {
+ pCell = aCol[nCol].GetCell( nRow );
+ if (pCell)
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ if (((ScFormulaCell*)pCell)->HasOneReference( aRef ))
+ if ( aRef.aStart.Col() == nCol && aRef.aEnd.Col() == nCol &&
+ aRef.aStart.Tab() == nTab && aRef.aEnd.Tab() == nTab &&
+ DiffSign( aRef.aStart.Row(), nRow ) ==
+ DiffSign( aRef.aEnd.Row(), nRow ) )
+ {
+ if (pArray->Insert( aRef.aStart.Row(), aRef.aEnd.Row(), bSizeChanged ))
+ {
+// ApplyPatternArea( nStartCol, nRow, nEndCol, nRow, aBoldPattern );
+ bFound = TRUE;
+ }
+ else
+ bMissed = TRUE;
+ }
+ }
+ }
+
+ delete[] pUsed;
+
+ // Spalten
+
+ pArray = pOutlineTable->GetColArray();
+ for (nCol=nStartCol; nCol<=nEndCol; nCol++)
+ {
+ if (!aCol[nCol].IsEmptyData())
+ {
+ bFound = FALSE;
+ ScColumnIterator aIter( &aCol[nCol], nStartRow, nEndRow );
+ while ( aIter.Next( nRow, pCell ) && !bFound )
+ {
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ if (((ScFormulaCell*)pCell)->HasOneReference( aRef ))
+ if ( aRef.aStart.Row() == nRow && aRef.aEnd.Row() == nRow &&
+ aRef.aStart.Tab() == nTab && aRef.aEnd.Tab() == nTab &&
+ DiffSign( aRef.aStart.Col(), nCol ) ==
+ DiffSign( aRef.aEnd.Col(), nCol ) )
+ {
+ if (pArray->Insert( aRef.aStart.Col(), aRef.aEnd.Col(), bSizeChanged ))
+ {
+// ApplyPatternArea( nCol, nStartRow, nCol, nEndRow, aBoldPattern );
+ bFound = TRUE;
+ }
+ else
+ bMissed = TRUE;
+ }
+ }
+ }
+ }
+}
+
+ // CopyData - fuer Query in anderen Bereich
+
+void ScTable::CopyData( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ SCCOL nDestCol, SCROW nDestRow, SCTAB nDestTab )
+{
+ //! wenn fuer mehrere Zeilen benutzt, nach Spalten optimieren!
+
+ ScAddress aSrc( nStartCol, nStartRow, nTab );
+ ScAddress aDest( nDestCol, nDestRow, nDestTab );
+ ScRange aRange( aSrc, aDest );
+ BOOL bThisTab = ( nDestTab == nTab );
+ SCROW nDestY = nDestRow;
+ for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
+ {
+ aSrc.SetRow( nRow );
+ aDest.SetRow( nDestY );
+ SCCOL nDestX = nDestCol;
+ for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
+ {
+ aSrc.SetCol( nCol );
+ aDest.SetCol( nDestX );
+ ScBaseCell* pCell = GetCell( nCol, nRow );
+ if (pCell)
+ {
+ pCell = pCell->CloneWithoutNote( *pDocument );
+ if (pCell->GetCellType() == CELLTYPE_FORMULA)
+ {
+ ((ScFormulaCell*)pCell)->UpdateReference( URM_COPY, aRange,
+ ((SCsCOL) nDestCol) - ((SCsCOL) nStartCol),
+ ((SCsROW) nDestRow) - ((SCsROW) nStartRow),
+ ((SCsTAB) nDestTab) - ((SCsTAB) nTab) );
+ ((ScFormulaCell*)pCell)->aPos = aDest;
+ }
+ }
+ if (bThisTab)
+ {
+ PutCell( nDestX, nDestY, pCell );
+ SetPattern( nDestX, nDestY, *GetPattern( nCol, nRow ), TRUE );
+ }
+ else
+ {
+ pDocument->PutCell( aDest, pCell );
+ pDocument->SetPattern( aDest, *GetPattern( nCol, nRow ), TRUE );
+ }
+
+ ++nDestX;
+ }
+ ++nDestY;
+ }
+}
+
+
+BOOL ScTable::RefVisible(ScFormulaCell* pCell)
+{
+ ScRange aRef;
+
+ if (pCell->HasOneReference(aRef))
+ {
+ if (aRef.aStart.Col()==aRef.aEnd.Col() && aRef.aStart.Tab()==aRef.aEnd.Tab() && pRowFlags)
+ {
+ // while ((value & CR_FILTERED) == CR_FILTERED)
+ // most times will be faster than
+ // while ((value & CR_FILTERED) == 0)
+ SCROW nEndRow = pRowFlags->GetBitStateEnd( aRef.aStart.Row(),
+ CR_FILTERED, CR_FILTERED);
+ if (!ValidRow(nEndRow) || nEndRow < aRef.aEnd.Row())
+ return TRUE; // at least partly visible
+ return FALSE; // completely unvisible
+ }
+ }
+
+ return TRUE; // irgendwie anders
+}
+
+
+void ScTable::GetUpperCellString(SCCOL nCol, SCROW nRow, String& rStr)
+{
+ GetInputString(nCol, nRow, rStr);
+ rStr.EraseTrailingChars();
+ rStr.EraseLeadingChars();
+ ScGlobal::pCharClass->toUpper(rStr);
+}
+
+
+// Berechnen der Groesse der Tabelle und setzen der Groesse an der DrawPage
+
+void ScTable::SetDrawPageSize()
+{
+ ScDrawLayer* pDrawLayer = pDocument->GetDrawLayer();
+ if( pDrawLayer )
+ {
+ long x = GetColOffset( MAXCOL + 1 );
+ long y = GetRowOffset( MAXROW + 1 );
+ x = (long) ((double) x * HMM_PER_TWIPS);
+ y = (long) ((double) y * HMM_PER_TWIPS);
+
+ if ( IsLayoutRTL() ) // IsNegativePage
+ x = -x;
+
+ pDrawLayer->SetPageSize( static_cast<sal_uInt16>(nTab), Size( x, y ) );
+ }
+}
+
+
+ULONG ScTable::GetRowOffset( SCROW nRow ) const
+{
+ ULONG n = 0;
+ if ( pRowFlags && pRowHeight )
+ {
+ if (nRow == 0)
+ return 0;
+ else if (nRow == 1)
+ return GetRowHeight(0);
+
+ n = pRowFlags->SumCoupledArrayForCondition( 0, nRow-1, CR_HIDDEN, 0,
+ *pRowHeight);
+#ifdef DBG_UTIL
+ if (n == ::std::numeric_limits<unsigned long>::max())
+ DBG_ERRORFILE("ScTable::GetRowOffset: row heights overflow");
+#endif
+ }
+ else
+ {
+ DBG_ERROR("GetRowOffset: Daten fehlen");
+ }
+ return n;
+}
+
+
+ULONG ScTable::GetColOffset( SCCOL nCol ) const
+{
+ ULONG n = 0;
+ if ( pColFlags && pColWidth )
+ {
+ SCCOL i;
+ BYTE* pFlags = pColFlags;
+ USHORT* pWidth = pColWidth;
+ for( i = 0; i < nCol; i++, pFlags++, pWidth++ )
+ if( !( *pFlags & CR_HIDDEN ) )
+ n += *pWidth;
+ }
+ else
+ {
+ DBG_ERROR("GetColumnOffset: Daten fehlen");
+ }
+ return n;
+}
+
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
new file mode 100644
index 000000000000..74f2a97e9c2e
--- /dev/null
+++ b/sc/source/core/data/table3.cxx
@@ -0,0 +1,1833 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: table3.cxx,v $
+ * $Revision: 1.30.128.1 $
+ *
+ * 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 <rtl/math.hxx>
+#include <unotools/textsearch.hxx>
+#include <svtools/zforlist.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/collatorwrapper.hxx>
+#include <com/sun/star/i18n/CollatorOptions.hpp>
+#include <stdlib.h>
+#include <unotools/transliterationwrapper.hxx>
+
+#include "table.hxx"
+#include "scitems.hxx"
+#include "collect.hxx"
+#include "attrib.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "globstr.hrc"
+#include "global.hxx"
+#include "stlpool.hxx"
+#include "compiler.hxx"
+#include "patattr.hxx"
+#include "subtotal.hxx"
+#include "docoptio.hxx"
+#include "markdata.hxx"
+#include "rangelst.hxx"
+#include "attarray.hxx"
+#include "userlist.hxx"
+#include "progress.hxx"
+#include "cellform.hxx"
+#include "postit.hxx"
+
+#include <vector>
+
+// STATIC DATA -----------------------------------------------------------
+
+const USHORT nMaxSorts = 3; // maximale Anzahl Sortierkriterien in aSortParam
+
+struct ScSortInfo
+{
+ ScBaseCell* pCell;
+ SCCOLROW nOrg;
+ DECL_FIXEDMEMPOOL_NEWDEL( ScSortInfo );
+};
+const USHORT nMemPoolSortInfo = (0x8000 - 64) / sizeof(ScSortInfo);
+IMPL_FIXEDMEMPOOL_NEWDEL( ScSortInfo, nMemPoolSortInfo, nMemPoolSortInfo )
+
+// END OF STATIC DATA -----------------------------------------------------
+
+
+class ScSortInfoArray
+{
+private:
+ ScSortInfo** pppInfo[nMaxSorts];
+ SCSIZE nCount;
+ SCCOLROW nStart;
+ USHORT nUsedSorts;
+
+public:
+ ScSortInfoArray( USHORT nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
+ nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ),
+ nUsedSorts( Min( nSorts, nMaxSorts ) )
+ {
+ for ( USHORT nSort = 0; nSort < nUsedSorts; nSort++ )
+ {
+ ScSortInfo** ppInfo = new ScSortInfo* [nCount];
+ for ( SCSIZE j = 0; j < nCount; j++ )
+ ppInfo[j] = new ScSortInfo;
+ pppInfo[nSort] = ppInfo;
+ }
+ }
+ ~ScSortInfoArray()
+ {
+ for ( USHORT nSort = 0; nSort < nUsedSorts; nSort++ )
+ {
+ ScSortInfo** ppInfo = pppInfo[nSort];
+ for ( SCSIZE j = 0; j < nCount; j++ )
+ delete ppInfo[j];
+ delete [] ppInfo;
+ }
+ }
+ ScSortInfo* Get( USHORT nSort, SCCOLROW nInd )
+ { return (pppInfo[nSort])[ nInd - nStart ]; }
+ void Swap( SCCOLROW nInd1, SCCOLROW nInd2 )
+ {
+ SCSIZE n1 = static_cast<SCSIZE>(nInd1 - nStart);
+ SCSIZE n2 = static_cast<SCSIZE>(nInd2 - nStart);
+ for ( USHORT nSort = 0; nSort < nUsedSorts; nSort++ )
+ {
+ ScSortInfo** ppInfo = pppInfo[nSort];
+ ScSortInfo* pTmp = ppInfo[n1];
+ ppInfo[n1] = ppInfo[n2];
+ ppInfo[n2] = pTmp;
+ }
+ }
+ USHORT GetUsedSorts() { return nUsedSorts; }
+ ScSortInfo** GetFirstArray() { return pppInfo[0]; }
+ SCCOLROW GetStart() { return nStart; }
+ SCSIZE GetCount() { return nCount; }
+};
+
+ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
+{
+ USHORT nUsedSorts = 1;
+ while ( nUsedSorts < nMaxSorts && aSortParam.bDoSort[nUsedSorts] )
+ nUsedSorts++;
+ ScSortInfoArray* pArray = new ScSortInfoArray( nUsedSorts, nInd1, nInd2 );
+ if ( aSortParam.bByRow )
+ {
+ for ( USHORT nSort = 0; nSort < nUsedSorts; nSort++ )
+ {
+ SCCOL nCol = static_cast<SCCOL>(aSortParam.nField[nSort]);
+ ScColumn* pCol = &aCol[nCol];
+ for ( SCROW nRow = nInd1; nRow <= nInd2; nRow++ )
+ {
+//2do: FillSortInfo an ScColumn und Array abklappern statt Search in GetCell
+ ScSortInfo* pInfo = pArray->Get( nSort, nRow );
+ pInfo->pCell = pCol->GetCell( nRow );
+ pInfo->nOrg = nRow;
+ }
+ }
+ }
+ else
+ {
+ for ( USHORT nSort = 0; nSort < nUsedSorts; nSort++ )
+ {
+ SCROW nRow = aSortParam.nField[nSort];
+ for ( SCCOL nCol = static_cast<SCCOL>(nInd1);
+ nCol <= static_cast<SCCOL>(nInd2); nCol++ )
+ {
+ ScSortInfo* pInfo = pArray->Get( nSort, nCol );
+ pInfo->pCell = GetCell( nCol, nRow );
+ pInfo->nOrg = nCol;
+ }
+ }
+ }
+ return pArray;
+}
+
+
+BOOL ScTable::IsSortCollatorGlobal() const
+{
+ return pSortCollator == ScGlobal::pCollator ||
+ pSortCollator == ScGlobal::pCaseCollator;
+}
+
+
+void ScTable::InitSortCollator( const ScSortParam& rPar )
+{
+ if ( rPar.aCollatorLocale.Language.getLength() )
+ {
+ if ( !pSortCollator || IsSortCollatorGlobal() )
+ pSortCollator = new CollatorWrapper( pDocument->GetServiceManager() );
+ pSortCollator->loadCollatorAlgorithm( rPar.aCollatorAlgorithm,
+ rPar.aCollatorLocale, (rPar.bCaseSens ? 0 : SC_COLLATOR_IGNORES) );
+ }
+ else
+ { // SYSTEM
+ DestroySortCollator();
+ pSortCollator = (rPar.bCaseSens ? ScGlobal::pCaseCollator :
+ ScGlobal::pCollator);
+ }
+}
+
+
+void ScTable::DestroySortCollator()
+{
+ if ( pSortCollator )
+ {
+ if ( !IsSortCollatorGlobal() )
+ delete pSortCollator;
+ pSortCollator = NULL;
+ }
+}
+
+
+void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress& rProgress )
+{
+ BOOL bByRow = aSortParam.bByRow;
+ SCSIZE nCount = pArray->GetCount();
+ ScSortInfo** ppInfo = pArray->GetFirstArray();
+ // hngngn.. Win16 legacy? Table has ULONG count but can only be initialized using USHORT :-/
+ // FIXME: use std::vector instead, would be better anyway (type safe)
+ USHORT nArghl = (nCount > USHRT_MAX ? USHRT_MAX : static_cast<USHORT>(nCount));
+ Table aTable( nArghl );
+ SCSIZE nPos;
+ for ( nPos = 0; nPos < nCount; nPos++ )
+ {
+ aTable.Insert( ppInfo[nPos]->nOrg, (void*) ppInfo[nPos] );
+ }
+ SCCOLROW nDest = pArray->GetStart();
+ for ( nPos = 0; nPos < nCount; nPos++, nDest++ )
+ {
+ SCCOLROW nOrg = ppInfo[nPos]->nOrg;
+ if ( nDest != nOrg )
+ {
+ if ( bByRow )
+ SwapRow( nDest, nOrg );
+ else
+ SwapCol( static_cast<SCCOL>(nDest), static_cast<SCCOL>(nOrg) );
+ // neue Position des weggeswapten eintragen
+ ScSortInfo* p = ppInfo[nPos];
+ p->nOrg = nDest;
+ p = (ScSortInfo*) aTable.Replace( nDest, (void*) p );
+ p->nOrg = nOrg;
+ p = (ScSortInfo*) aTable.Replace( nOrg, (void*) p );
+ DBG_ASSERT( p == ppInfo[nPos], "SortReorder: nOrg MisMatch" );
+ }
+ rProgress.SetStateOnPercent( nPos );
+ }
+}
+
+short ScTable::CompareCell( USHORT nSort,
+ ScBaseCell* pCell1, SCCOL nCell1Col, SCROW nCell1Row,
+ ScBaseCell* pCell2, SCCOL nCell2Col, SCROW nCell2Row )
+{
+ short nRes = 0;
+
+ CellType eType1 = CELLTYPE_NONE, eType2 = CELLTYPE_NONE;
+ if (pCell1)
+ {
+ eType1 = pCell1->GetCellType();
+ if (eType1 == CELLTYPE_NOTE)
+ pCell1 = NULL;
+ }
+ if (pCell2)
+ {
+ eType2 = pCell2->GetCellType();
+ if (eType2 == CELLTYPE_NOTE)
+ pCell2 = NULL;
+ }
+
+ if (pCell1)
+ {
+ if (pCell2)
+ {
+ BOOL bStr1 = ( eType1 != CELLTYPE_VALUE );
+ if ( eType1 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell1)->IsValue() )
+ bStr1 = FALSE;
+ BOOL bStr2 = ( eType2 != CELLTYPE_VALUE );
+ if ( eType2 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell2)->IsValue() )
+ bStr2 = FALSE;
+
+ if ( bStr1 && bStr2 ) // nur Strings untereinander als String vergleichen!
+ {
+ String aStr1;
+ String aStr2;
+ if (eType1 == CELLTYPE_STRING)
+ ((ScStringCell*)pCell1)->GetString(aStr1);
+ else
+ GetString(nCell1Col, nCell1Row, aStr1);
+ if (eType2 == CELLTYPE_STRING)
+ ((ScStringCell*)pCell2)->GetString(aStr2);
+ else
+ GetString(nCell2Col, nCell2Row, aStr2);
+ BOOL bUserDef = aSortParam.bUserDef;
+ if (bUserDef)
+ {
+ ScUserListData* pData =
+ (ScUserListData*)(ScGlobal::GetUserList()->At(
+ aSortParam.nUserIndex));
+ if (pData)
+ {
+ if ( aSortParam.bCaseSens )
+ nRes = sal::static_int_cast<short>( pData->Compare(aStr1, aStr2) );
+ else
+ nRes = sal::static_int_cast<short>( pData->ICompare(aStr1, aStr2) );
+ }
+ else
+ bUserDef = FALSE;
+
+ }
+ if (!bUserDef)
+ nRes = (short) pSortCollator->compareString( aStr1, aStr2 );
+ }
+ else if ( bStr1 ) // String <-> Zahl
+ nRes = 1; // Zahl vorne
+ else if ( bStr2 ) // Zahl <-> String
+ nRes = -1; // Zahl vorne
+ else // Zahlen untereinander
+ {
+ double nVal1;
+ double nVal2;
+ if (eType1 == CELLTYPE_VALUE)
+ nVal1 = ((ScValueCell*)pCell1)->GetValue();
+ else if (eType1 == CELLTYPE_FORMULA)
+ nVal1 = ((ScFormulaCell*)pCell1)->GetValue();
+ else
+ nVal1 = 0;
+ if (eType2 == CELLTYPE_VALUE)
+ nVal2 = ((ScValueCell*)pCell2)->GetValue();
+ else if (eType2 == CELLTYPE_FORMULA)
+ nVal2 = ((ScFormulaCell*)pCell2)->GetValue();
+ else
+ nVal2 = 0;
+ if (nVal1 < nVal2)
+ nRes = -1;
+ else if (nVal1 > nVal2)
+ nRes = 1;
+ }
+ if ( !aSortParam.bAscending[nSort] )
+ nRes = -nRes;
+ }
+ else
+ nRes = -1;
+ }
+ else
+ {
+ if ( pCell2 )
+ nRes = 1;
+ else
+ nRes = 0; // beide leer
+ }
+ return nRes;
+}
+
+short ScTable::Compare( ScSortInfoArray* pArray, SCCOLROW nIndex1, SCCOLROW nIndex2 )
+{
+ short nRes;
+ USHORT nSort = 0;
+ do
+ {
+ ScSortInfo* pInfo1 = pArray->Get( nSort, nIndex1 );
+ ScSortInfo* pInfo2 = pArray->Get( nSort, nIndex2 );
+ if ( aSortParam.bByRow )
+ nRes = CompareCell( nSort,
+ pInfo1->pCell, static_cast<SCCOL>(aSortParam.nField[nSort]), pInfo1->nOrg,
+ pInfo2->pCell, static_cast<SCCOL>(aSortParam.nField[nSort]), pInfo2->nOrg );
+ else
+ nRes = CompareCell( nSort,
+ pInfo1->pCell, static_cast<SCCOL>(pInfo1->nOrg), aSortParam.nField[nSort],
+ pInfo2->pCell, static_cast<SCCOL>(pInfo2->nOrg), aSortParam.nField[nSort] );
+ } while ( nRes == 0 && ++nSort < pArray->GetUsedSorts() );
+ if( nRes == 0 )
+ {
+ ScSortInfo* pInfo1 = pArray->Get( 0, nIndex1 );
+ ScSortInfo* pInfo2 = pArray->Get( 0, nIndex2 );
+ if( pInfo1->nOrg < pInfo2->nOrg )
+ nRes = -1;
+ else if( pInfo1->nOrg > pInfo2->nOrg )
+ nRes = 1;
+ }
+ return nRes;
+}
+
+void ScTable::QuickSort( ScSortInfoArray* pArray, SCsCOLROW nLo, SCsCOLROW nHi )
+{
+ if ((nHi - nLo) == 1)
+ {
+ if (Compare(pArray, nLo, nHi) > 0)
+ pArray->Swap( nLo, nHi );
+ }
+ else
+ {
+ SCsCOLROW ni = nLo;
+ SCsCOLROW nj = nHi;
+ do
+ {
+ while ((ni <= nHi) && (Compare(pArray, ni, nLo)) < 0)
+ ni++;
+ while ((nj >= nLo) && (Compare(pArray, nLo, nj)) < 0)
+ nj--;
+ if (ni <= nj)
+ {
+ if (ni != nj)
+ pArray->Swap( ni, nj );
+ ni++;
+ nj--;
+ }
+ } while (ni < nj);
+ if ((nj - nLo) < (nHi - ni))
+ {
+ if (nLo < nj)
+ QuickSort(pArray, nLo, nj);
+ if (ni < nHi)
+ QuickSort(pArray, ni, nHi);
+ }
+ else
+ {
+ if (ni < nHi)
+ QuickSort(pArray, ni, nHi);
+ if (nLo < nj)
+ QuickSort(pArray, nLo, nj);
+ }
+ }
+}
+
+void ScTable::SwapCol(SCCOL nCol1, SCCOL nCol2)
+{
+ for (SCROW nRow = aSortParam.nRow1; nRow <= aSortParam.nRow2; nRow++)
+ {
+ aCol[nCol1].SwapCell(nRow, aCol[nCol2]);
+ if (aSortParam.bIncludePattern)
+ {
+ const ScPatternAttr* pPat1 = GetPattern(nCol1, nRow);
+ const ScPatternAttr* pPat2 = GetPattern(nCol2, nRow);
+ if (pPat1 != pPat2)
+ {
+ SetPattern(nCol1, nRow, *pPat2, TRUE);
+ SetPattern(nCol2, nRow, *pPat1, TRUE);
+ }
+ }
+ }
+}
+
+void ScTable::SwapRow(SCROW nRow1, SCROW nRow2)
+{
+ for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; nCol++)
+ {
+ aCol[nCol].SwapRow(nRow1, nRow2);
+ if (aSortParam.bIncludePattern)
+ {
+ const ScPatternAttr* pPat1 = GetPattern(nCol, nRow1);
+ const ScPatternAttr* pPat2 = GetPattern(nCol, nRow2);
+ if (pPat1 != pPat2)
+ {
+ SetPattern(nCol, nRow1, *pPat2, TRUE);
+ SetPattern(nCol, nRow2, *pPat1, TRUE);
+ }
+ }
+ }
+ if (bGlobalKeepQuery && pRowFlags)
+ {
+ BYTE nRow1Flags = pRowFlags->GetValue(nRow1);
+ BYTE nRow2Flags = pRowFlags->GetValue(nRow2);
+ BYTE nFlags1 = nRow1Flags & ( CR_HIDDEN | CR_FILTERED );
+ BYTE nFlags2 = nRow2Flags & ( CR_HIDDEN | CR_FILTERED );
+ pRowFlags->SetValue( nRow1, (nRow1Flags & ~( CR_HIDDEN | CR_FILTERED )) | nFlags2);
+ pRowFlags->SetValue( nRow2, (nRow2Flags & ~( CR_HIDDEN | CR_FILTERED )) | nFlags1);
+ }
+}
+
+short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2)
+{
+ short nRes;
+ USHORT nSort = 0;
+ if (aSortParam.bByRow)
+ {
+ do
+ {
+ SCCOL nCol = static_cast<SCCOL>(aSortParam.nField[nSort]);
+ ScBaseCell* pCell1 = aCol[nCol].GetCell( nIndex1 );
+ ScBaseCell* pCell2 = aCol[nCol].GetCell( nIndex2 );
+ nRes = CompareCell( nSort, pCell1, nCol, nIndex1, pCell2, nCol, nIndex2 );
+ } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.bDoSort[nSort] );
+ }
+ else
+ {
+ do
+ {
+ SCROW nRow = aSortParam.nField[nSort];
+ ScBaseCell* pCell1 = aCol[nIndex1].GetCell( nRow );
+ ScBaseCell* pCell2 = aCol[nIndex2].GetCell( nRow );
+ nRes = CompareCell( nSort, pCell1, static_cast<SCCOL>(nIndex1),
+ nRow, pCell2, static_cast<SCCOL>(nIndex2), nRow );
+ } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.bDoSort[nSort] );
+ }
+ return nRes;
+}
+
+BOOL ScTable::IsSorted( SCCOLROW nStart, SCCOLROW nEnd ) // ueber aSortParam
+{
+ for (SCCOLROW i=nStart; i<nEnd; i++)
+ {
+ if (Compare( i, i+1 ) > 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void ScTable::DecoladeRow( ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2 )
+{
+ SCROW nRow;
+ SCROW nMax = nRow2 - nRow1;
+ for (SCROW i = nRow1; (i + 4) <= nRow2; i += 4)
+ {
+ nRow = rand() % nMax;
+ pArray->Swap(i, nRow1 + nRow);
+ }
+}
+
+void ScTable::Sort(const ScSortParam& rSortParam, BOOL bKeepQuery)
+{
+ aSortParam = rSortParam;
+ InitSortCollator( rSortParam );
+ bGlobalKeepQuery = bKeepQuery;
+ if (rSortParam.bByRow)
+ {
+ SCROW nLastRow = 0;
+ for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; nCol++)
+ nLastRow = Max(nLastRow, aCol[nCol].GetLastDataPos());
+ nLastRow = Min(nLastRow, aSortParam.nRow2);
+ SCROW nRow1 = (rSortParam.bHasHeader ?
+ aSortParam.nRow1 + 1 : aSortParam.nRow1);
+ if (!IsSorted(nRow1, nLastRow))
+ {
+ ScProgress aProgress( pDocument->GetDocumentShell(),
+ ScGlobal::GetRscString(STR_PROGRESS_SORTING), nLastRow - nRow1 );
+ ScSortInfoArray* pArray = CreateSortInfoArray( nRow1, nLastRow );
+ if ( nLastRow - nRow1 > 255 )
+ DecoladeRow( pArray, nRow1, nLastRow );
+ QuickSort( pArray, nRow1, nLastRow );
+ SortReorder( pArray, aProgress );
+ delete pArray;
+ // #158377# #i59745# update position of caption objects of cell notes
+ ScNoteUtil::UpdateCaptionPositions( *pDocument, ScRange( aSortParam.nCol1, nRow1, nTab, aSortParam.nCol2, nLastRow, nTab ) );
+ }
+ }
+ else
+ {
+ SCCOL nLastCol;
+ for (nLastCol = aSortParam.nCol2;
+ (nLastCol > aSortParam.nCol1) && aCol[nLastCol].IsEmptyBlock(aSortParam.nRow1, aSortParam.nRow2); nLastCol--)
+ {
+ }
+ SCCOL nCol1 = (rSortParam.bHasHeader ?
+ aSortParam.nCol1 + 1 : aSortParam.nCol1);
+ if (!IsSorted(nCol1, nLastCol))
+ {
+ ScProgress aProgress( pDocument->GetDocumentShell(),
+ ScGlobal::GetRscString(STR_PROGRESS_SORTING), nLastCol - nCol1 );
+ ScSortInfoArray* pArray = CreateSortInfoArray( nCol1, nLastCol );
+ QuickSort( pArray, nCol1, nLastCol );
+ SortReorder( pArray, aProgress );
+ delete pArray;
+ // #158377# #i59745# update position of caption objects of cell notes
+ ScNoteUtil::UpdateCaptionPositions( *pDocument, ScRange( nCol1, aSortParam.nRow1, nTab, nLastCol, aSortParam.nRow2, nTab ) );
+ }
+ }
+ DestroySortCollator();
+}
+
+
+// Testen, ob beim Loeschen von Zwischenergebnissen andere Daten mit geloescht werden
+// (fuer Hinweis-Box)
+
+BOOL ScTable::TestRemoveSubTotals( const ScSubTotalParam& rParam )
+{
+ SCCOL nStartCol = rParam.nCol1;
+ SCROW nStartRow = rParam.nRow1 + 1; // Header
+ SCCOL nEndCol = rParam.nCol2;
+ SCROW nEndRow = rParam.nRow2;
+
+ SCCOL nCol;
+ SCROW nRow;
+ ScBaseCell* pCell;
+
+ BOOL bWillDelete = FALSE;
+ for ( nCol=nStartCol; nCol<=nEndCol && !bWillDelete; nCol++ )
+ {
+ ScColumnIterator aIter( &aCol[nCol],nStartRow,nEndRow );
+ while ( aIter.Next( nRow, pCell ) && !bWillDelete )
+ {
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ if (((ScFormulaCell*)pCell)->IsSubTotal())
+ {
+ for (SCCOL nTestCol=0; nTestCol<=MAXCOL; nTestCol++)
+ if (nTestCol<nStartCol || nTestCol>nEndCol)
+ if (aCol[nTestCol].HasDataAt(nRow))
+ bWillDelete = TRUE;
+ }
+ }
+ }
+ return bWillDelete;
+}
+
+// alte Ergebnisse loeschen
+// rParam.nRow2 wird veraendert !
+
+void ScTable::RemoveSubTotals( ScSubTotalParam& rParam )
+{
+ SCCOL nStartCol = rParam.nCol1;
+ SCROW nStartRow = rParam.nRow1 + 1; // Header
+ SCCOL nEndCol = rParam.nCol2;
+ SCROW nEndRow = rParam.nRow2; // wird veraendert
+
+ SCCOL nCol;
+ SCROW nRow;
+ ScBaseCell* pCell;
+
+ for ( nCol=nStartCol; nCol<=nEndCol; nCol++ )
+ {
+ ScColumnIterator aIter( &aCol[nCol],nStartRow,nEndRow );
+ while ( aIter.Next( nRow, pCell ) )
+ {
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ if (((ScFormulaCell*)pCell)->IsSubTotal())
+ {
+ SetRowFlags(nRow+1,GetRowFlags(nRow+1)&(~CR_MANUALBREAK));
+ pDocument->DeleteRow( 0,nTab, MAXCOL,nTab, nRow, 1 );
+ --nEndRow;
+ aIter = ScColumnIterator( &aCol[nCol],nRow,nEndRow );
+ }
+ }
+ }
+
+ rParam.nRow2 = nEndRow; // neues Ende
+}
+
+// harte Zahlenformate loeschen (fuer Ergebnisformeln)
+
+void lcl_RemoveNumberFormat( ScTable* pTab, SCCOL nCol, SCROW nRow )
+{
+ const ScPatternAttr* pPattern = pTab->GetPattern( nCol, nRow );
+ if ( pPattern->GetItemSet().GetItemState( ATTR_VALUE_FORMAT, FALSE )
+ == SFX_ITEM_SET )
+ {
+ ScPatternAttr aNewPattern( *pPattern );
+ SfxItemSet& rSet = aNewPattern.GetItemSet();
+ rSet.ClearItem( ATTR_VALUE_FORMAT );
+ rSet.ClearItem( ATTR_LANGUAGE_FORMAT );
+ pTab->SetPattern( nCol, nRow, aNewPattern, TRUE );
+ }
+}
+
+
+// at least MSC needs this at linkage level to be able to use it in a template
+typedef struct lcl_ScTable_DoSubTotals_RowEntry
+{
+ USHORT nGroupNo;
+ SCROW nSubStartRow;
+ SCROW nDestRow;
+ SCROW nFuncStart;
+ SCROW nFuncEnd;
+} RowEntry;
+
+// neue Zwischenergebnisse
+// rParam.nRow2 wird veraendert !
+
+BOOL ScTable::DoSubTotals( ScSubTotalParam& rParam )
+{
+ SCCOL nStartCol = rParam.nCol1;
+ SCROW nStartRow = rParam.nRow1 + 1; // Header
+ SCCOL nEndCol = rParam.nCol2;
+ SCROW nEndRow = rParam.nRow2; // wird veraendert
+ USHORT i;
+
+ // Leerzeilen am Ende weglassen,
+ // damit alle Ueberlaeufe (MAXROW) bei InsertRow gefunden werden (#35180#)
+ // Wenn sortiert wurde, sind alle Leerzeilen am Ende.
+ SCSIZE nEmpty = GetEmptyLinesInBlock( nStartCol, nStartRow, nEndCol, nEndRow, DIR_BOTTOM );
+ nEndRow -= nEmpty;
+
+ USHORT nLevelCount = 0; // Anzahl Gruppierungen
+ BOOL bDoThis = TRUE;
+ for (i=0; i<MAXSUBTOTAL && bDoThis; i++)
+ if (rParam.bGroupActive[i])
+ nLevelCount = i+1;
+ else
+ bDoThis = FALSE;
+
+ if (nLevelCount==0) // nichts tun
+ return TRUE;
+
+ SCCOL* nGroupCol = rParam.nField; // Spalten nach denen
+ // gruppiert wird
+
+ // #44444# Durch (leer) als eigene Kategorie muss immer auf
+ // Teilergebniszeilen aus den anderen Spalten getestet werden
+ // (frueher nur, wenn eine Spalte mehrfach vorkam)
+ BOOL bTestPrevSub = ( nLevelCount > 1 );
+
+ String aSubString;
+ String aOutString;
+
+ BOOL bIgnoreCase = !rParam.bCaseSens;
+
+ String *pCompString[MAXSUBTOTAL]; // Pointer wegen Compiler-Problemen
+ for (i=0; i<MAXSUBTOTAL; i++)
+ pCompString[i] = new String;
+
+ //! sortieren?
+
+ ScStyleSheet* pStyle = (ScStyleSheet*) pDocument->GetStyleSheetPool()->Find(
+ ScGlobal::GetRscString(STR_STYLENAME_RESULT), SFX_STYLE_FAMILY_PARA );
+
+ BOOL bSpaceLeft = TRUE; // Erfolg beim Einfuegen?
+
+ // #90279# For performance reasons collect formula entries so their
+ // references don't have to be tested for updates each time a new row is
+ // inserted
+ RowEntry aRowEntry;
+ ::std::vector< RowEntry > aRowVector;
+
+ for (USHORT nLevel=0; nLevel<=nLevelCount && bSpaceLeft; nLevel++) // incl. Gesamtergebnis
+ {
+ BOOL bTotal = ( nLevel == nLevelCount );
+ aRowEntry.nGroupNo = bTotal ? 0 : (nLevelCount-nLevel-1);
+
+ // how many results per level
+ SCCOL nResCount = rParam.nSubTotals[aRowEntry.nGroupNo];
+ // result functions
+ ScSubTotalFunc* eResFunc = rParam.pFunctions[aRowEntry.nGroupNo];
+
+ if (nResCount > 0) // sonst nur sortieren
+ {
+ for (i=0; i<=aRowEntry.nGroupNo; i++)
+ {
+ GetString( nGroupCol[i], nStartRow, aSubString );
+ if ( bIgnoreCase )
+ *pCompString[i] = ScGlobal::pCharClass->upper( aSubString );
+ else
+ *pCompString[i] = aSubString;
+ } // aSubString bleibt auf dem letzten stehen
+
+ BOOL bBlockVis = FALSE; // Gruppe eingeblendet?
+ aRowEntry.nSubStartRow = nStartRow;
+ for (SCROW nRow=nStartRow; nRow<=nEndRow+1 && bSpaceLeft; nRow++)
+ {
+ BOOL bChanged;
+ if (nRow>nEndRow)
+ bChanged = TRUE;
+ else
+ {
+ bChanged = FALSE;
+ if (!bTotal)
+ {
+ String aString;
+ for (i=0; i<=aRowEntry.nGroupNo && !bChanged; i++)
+ {
+ GetString( nGroupCol[i], nRow, aString );
+ if (bIgnoreCase)
+ ScGlobal::pCharClass->toUpper( aString );
+ // #41427# wenn sortiert, ist "leer" eine eigene Gruppe
+ // sonst sind leere Zellen unten erlaubt
+ bChanged = ( ( aString.Len() || rParam.bDoSort ) &&
+ aString != *pCompString[i] );
+ }
+ if ( bChanged && bTestPrevSub )
+ {
+ // No group change on rows that will contain subtotal formulas
+ for ( ::std::vector< RowEntry >::const_iterator
+ iEntry( aRowVector.begin());
+ iEntry != aRowVector.end(); ++iEntry)
+ {
+ if ( iEntry->nDestRow == nRow )
+ {
+ bChanged = FALSE;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if ( bChanged )
+ {
+ aRowEntry.nDestRow = nRow;
+ aRowEntry.nFuncStart = aRowEntry.nSubStartRow;
+ aRowEntry.nFuncEnd = nRow-1;
+
+ bSpaceLeft = pDocument->InsertRow( 0, nTab, MAXCOL, nTab,
+ aRowEntry.nDestRow, 1 );
+ DBShowRow( aRowEntry.nDestRow, bBlockVis );
+ bBlockVis = FALSE;
+ if ( rParam.bPagebreak && nRow < MAXROW &&
+ aRowEntry.nSubStartRow != nStartRow && nLevel == 0)
+ SetRowFlags( aRowEntry.nSubStartRow,
+ GetRowFlags(aRowEntry.nSubStartRow) |
+ CR_MANUALBREAK);
+
+ if (bSpaceLeft)
+ {
+ for ( ::std::vector< RowEntry >::iterator iMove(
+ aRowVector.begin() );
+ iMove != aRowVector.end(); ++iMove)
+ {
+ if ( aRowEntry.nDestRow <= iMove->nSubStartRow )
+ ++iMove->nSubStartRow;
+ if ( aRowEntry.nDestRow <= iMove->nDestRow )
+ ++iMove->nDestRow;
+ if ( aRowEntry.nDestRow <= iMove->nFuncStart )
+ ++iMove->nFuncStart;
+ if ( aRowEntry.nDestRow <= iMove->nFuncEnd )
+ ++iMove->nFuncEnd;
+ }
+ // collect formula positions
+ aRowVector.push_back( aRowEntry );
+
+ if (bTotal) // "Gesamtergebnis"
+ aOutString = ScGlobal::GetRscString( STR_TABLE_GESAMTERGEBNIS );
+ else
+ { // " Ergebnis"
+ aOutString = aSubString;
+ if (!aOutString.Len())
+ aOutString = ScGlobal::GetRscString( STR_EMPTYDATA );
+ aOutString += ' ';
+ USHORT nStrId = STR_TABLE_ERGEBNIS;
+ if ( nResCount == 1 )
+ switch ( eResFunc[0] )
+ {
+ case SUBTOTAL_FUNC_AVE: nStrId = STR_FUN_TEXT_AVG; break;
+ case SUBTOTAL_FUNC_CNT:
+ case SUBTOTAL_FUNC_CNT2: nStrId = STR_FUN_TEXT_COUNT; break;
+ case SUBTOTAL_FUNC_MAX: nStrId = STR_FUN_TEXT_MAX; break;
+ case SUBTOTAL_FUNC_MIN: nStrId = STR_FUN_TEXT_MIN; break;
+ case SUBTOTAL_FUNC_PROD: nStrId = STR_FUN_TEXT_PRODUCT; break;
+ case SUBTOTAL_FUNC_STD:
+ case SUBTOTAL_FUNC_STDP: nStrId = STR_FUN_TEXT_STDDEV; break;
+ case SUBTOTAL_FUNC_SUM: nStrId = STR_FUN_TEXT_SUM; break;
+ case SUBTOTAL_FUNC_VAR:
+ case SUBTOTAL_FUNC_VARP: nStrId = STR_FUN_TEXT_VAR; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ aOutString += ScGlobal::GetRscString( nStrId );
+ }
+ SetString( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, aOutString );
+ ApplyStyle( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, *pStyle );
+
+/* if (rParam.bPagebreak && nRow < MAXROW)
+ {
+ BYTE nFlags = GetRowFlags( nRow+1 );
+ nFlags |= CR_MANUALBREAK;
+ SetRowFlags( nRow+1, nFlags );
+ }
+*/
+ ++nRow;
+ ++nEndRow;
+ aRowEntry.nSubStartRow = nRow;
+ for (i=0; i<=aRowEntry.nGroupNo; i++)
+ {
+ GetString( nGroupCol[i], nRow, aSubString );
+ if ( bIgnoreCase )
+ *pCompString[i] = ScGlobal::pCharClass->upper( aSubString );
+ else
+ *pCompString[i] = aSubString;
+ }
+ }
+ }
+ if (!pRowFlags)
+ bBlockVis = TRUE;
+ else
+ if ( (pRowFlags->GetValue(nRow) & CR_FILTERED) == 0 )
+ bBlockVis = TRUE;
+ }
+ }
+ else
+ {
+// DBG_ERROR( "nSubTotals==0 bei DoSubTotals" );
+ }
+ }
+
+ // now insert the formulas
+ ScComplexRefData aRef;
+ aRef.InitFlags();
+ aRef.Ref1.nTab = nTab;
+ aRef.Ref2.nTab = nTab;
+ for ( ::std::vector< RowEntry >::const_iterator iEntry( aRowVector.begin());
+ iEntry != aRowVector.end(); ++iEntry)
+ {
+ SCCOL nResCount = rParam.nSubTotals[iEntry->nGroupNo];
+ SCCOL* nResCols = rParam.pSubTotals[iEntry->nGroupNo];
+ ScSubTotalFunc* eResFunc = rParam.pFunctions[iEntry->nGroupNo];
+ for ( SCCOL nResult=0; nResult < nResCount; ++nResult )
+ {
+ aRef.Ref1.nCol = nResCols[nResult];
+ aRef.Ref1.nRow = iEntry->nFuncStart;
+ aRef.Ref2.nCol = nResCols[nResult];
+ aRef.Ref2.nRow = iEntry->nFuncEnd;
+
+ ScTokenArray aArr;
+ aArr.AddOpCode( ocSubTotal );
+ aArr.AddOpCode( ocOpen );
+ aArr.AddDouble( (double) eResFunc[nResult] );
+ aArr.AddOpCode( ocSep );
+ aArr.AddDoubleReference( aRef );
+ aArr.AddOpCode( ocClose );
+ aArr.AddOpCode( ocStop );
+ ScBaseCell* pCell = new ScFormulaCell( pDocument, ScAddress(
+ nResCols[nResult], iEntry->nDestRow, nTab), &aArr );
+ PutCell( nResCols[nResult], iEntry->nDestRow, pCell );
+
+ if ( nResCols[nResult] != nGroupCol[iEntry->nGroupNo] )
+ {
+ ApplyStyle( nResCols[nResult], iEntry->nDestRow, *pStyle );
+
+ // Zahlformat loeschen
+ lcl_RemoveNumberFormat( this, nResCols[nResult], iEntry->nDestRow );
+ }
+ }
+
+ }
+
+ //! je nach Einstellung Zwischensummen-Zeilen nach oben verschieben ?
+
+ //! Outlines direkt erzeugen?
+
+ if (bSpaceLeft)
+ DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
+
+ for (i=0; i<MAXSUBTOTAL; i++)
+ delete pCompString[i];
+
+ rParam.nRow2 = nEndRow; // neues Ende
+ return bSpaceLeft;
+}
+
+
+BOOL ScTable::ValidQuery(SCROW nRow, const ScQueryParam& rParam,
+ BOOL* pSpecial /* =NULL */ , ScBaseCell* pCell /* =NULL */ ,
+ BOOL* pbTestEqualCondition /* = NULL */ )
+{
+ if (!rParam.GetEntry(0).bDoQuery)
+ return TRUE;
+
+ //---------------------------------------------------------------
+
+ const SCSIZE nFixedBools = 32;
+ BOOL aBool[nFixedBools];
+ BOOL aTest[nFixedBools];
+ SCSIZE nEntryCount = rParam.GetEntryCount();
+ BOOL* pPasst = ( nEntryCount <= nFixedBools ? &aBool[0] : new BOOL[nEntryCount] );
+ BOOL* pTest = ( nEntryCount <= nFixedBools ? &aTest[0] : new BOOL[nEntryCount] );
+
+ long nPos = -1;
+ SCSIZE i = 0;
+ BOOL bMatchWholeCell = pDocument->GetDocOptions().IsMatchWholeCell();
+ CollatorWrapper* pCollator = (rParam.bCaseSens ? ScGlobal::pCaseCollator :
+ ScGlobal::pCollator);
+ ::utl::TransliterationWrapper* pTransliteration = (rParam.bCaseSens ?
+ ScGlobal::pCaseTransliteration : ScGlobal::pTransliteration);
+
+ while ( (i < nEntryCount) && rParam.GetEntry(i).bDoQuery )
+ {
+ ScQueryEntry& rEntry = rParam.GetEntry(i);
+ // we can only handle one single direct query
+ if ( !pCell || i > 0 )
+ pCell = GetCell( static_cast<SCCOL>(rEntry.nField), nRow );
+
+ BOOL bOk = FALSE;
+ BOOL bTestEqual = FALSE;
+
+ if ( pSpecial && pSpecial[i] )
+ {
+ if (rEntry.nVal == SC_EMPTYFIELDS)
+ bOk = !( aCol[rEntry.nField].HasDataAt( nRow ) );
+ else // if (rEntry.nVal == SC_NONEMPTYFIELDS)
+ bOk = aCol[rEntry.nField].HasDataAt( nRow );
+ }
+ else if ( !rEntry.bQueryByString && (pCell ? pCell->HasValueData() :
+ HasValueData( static_cast<SCCOL>(rEntry.nField), nRow)))
+ { // by Value
+ double nCellVal;
+ if ( pCell )
+ {
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ nCellVal = ((ScValueCell*)pCell)->GetValue();
+ break;
+ case CELLTYPE_FORMULA :
+ nCellVal = ((ScFormulaCell*)pCell)->GetValue();
+ break;
+ default:
+ nCellVal = 0.0;
+ }
+
+ }
+ else
+ nCellVal = GetValue( static_cast<SCCOL>(rEntry.nField), nRow );
+ switch (rEntry.eOp)
+ {
+ case SC_EQUAL :
+ bOk = ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
+ break;
+ case SC_LESS :
+ bOk = (nCellVal < rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
+ break;
+ case SC_GREATER :
+ bOk = (nCellVal > rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
+ break;
+ case SC_LESS_EQUAL :
+ bOk = (nCellVal < rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
+ if ( bOk && pbTestEqualCondition )
+ bTestEqual = ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
+ break;
+ case SC_GREATER_EQUAL :
+ bOk = (nCellVal > rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
+ if ( bOk && pbTestEqualCondition )
+ bTestEqual = ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
+ break;
+ case SC_NOT_EQUAL :
+ bOk = !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else if ( (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL) ||
+ (rEntry.bQueryByString && (pCell ? pCell->HasStringData() :
+ HasStringData(
+ static_cast<SCCOL>(rEntry.nField),
+ nRow))))
+ { // by String
+ String aCellStr;
+ if ( pCell )
+ {
+ if (pCell->GetCellType() != CELLTYPE_NOTE)
+ {
+ ULONG nFormat = GetNumberFormat( static_cast<SCCOL>(rEntry.nField), nRow );
+ ScCellFormat::GetInputString( pCell, nFormat, aCellStr, *(pDocument->GetFormatTable()) );
+ }
+ }
+ else
+ GetInputString( static_cast<SCCOL>(rEntry.nField), nRow, aCellStr );
+
+ BOOL bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL)
+ || (rEntry.eOp == SC_NOT_EQUAL)));
+ BOOL bTestRegExp = (pbTestEqualCondition && rParam.bRegExp
+ && ((rEntry.eOp == SC_LESS_EQUAL)
+ || (rEntry.eOp == SC_GREATER_EQUAL)));
+ if ( bRealRegExp || bTestRegExp )
+ {
+ xub_StrLen nStart = 0;
+ xub_StrLen nEnd = aCellStr.Len();
+ BOOL bMatch = (BOOL) rEntry.GetSearchTextPtr( rParam.bCaseSens )
+ ->SearchFrwrd( aCellStr, &nStart, &nEnd );
+ // from 614 on, nEnd is behind the found text
+ if ( bMatch && bMatchWholeCell
+ && (nStart != 0 || nEnd != aCellStr.Len()) )
+ bMatch = FALSE; // RegExp must match entire cell string
+ if ( bRealRegExp )
+ bOk = ((rEntry.eOp == SC_NOT_EQUAL) ? !bMatch : bMatch);
+ else
+ bTestEqual = bMatch;
+ }
+ if ( !bRealRegExp )
+ {
+ if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL )
+ {
+ if ( !rEntry.bQueryByString && rEntry.pStr->Len() == 0 )
+ {
+ // #i18374# When used from functions (match, countif, sumif, vlookup, hlookup, lookup),
+ // the query value is assigned directly, and the string is empty. In that case,
+ // don't find any string (isEqual would find empty string results in formula cells).
+ bOk = FALSE;
+ }
+ else if ( bMatchWholeCell )
+ bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr );
+ else
+ {
+ ::com::sun::star::uno::Sequence< sal_Int32 > xOff;
+ String aCell( pTransliteration->transliterate(
+ aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(),
+ &xOff ) );
+ String aQuer( pTransliteration->transliterate(
+ *rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(),
+ &xOff ) );
+ bOk = (aCell.Search( aQuer ) != STRING_NOTFOUND);
+ }
+ if ( rEntry.eOp == SC_NOT_EQUAL )
+ bOk = !bOk;
+ }
+ else
+ { // use collator here because data was probably sorted
+ sal_Int32 nCompare = pCollator->compareString(
+ aCellStr, *rEntry.pStr );
+ switch (rEntry.eOp)
+ {
+ case SC_LESS :
+ bOk = (nCompare < 0);
+ break;
+ case SC_GREATER :
+ bOk = (nCompare > 0);
+ break;
+ case SC_LESS_EQUAL :
+ bOk = (nCompare <= 0);
+ if ( bOk && pbTestEqualCondition && !bTestEqual )
+ bTestEqual = (nCompare == 0);
+ break;
+ case SC_GREATER_EQUAL :
+ bOk = (nCompare >= 0);
+ if ( bOk && pbTestEqualCondition && !bTestEqual )
+ bTestEqual = (nCompare == 0);
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ }
+ else if (rParam.bMixedComparison)
+ {
+ if (rEntry.bQueryByString &&
+ (rEntry.eOp == SC_LESS || rEntry.eOp == SC_LESS_EQUAL) &&
+ (pCell ? pCell->HasValueData() :
+ HasValueData( static_cast<SCCOL>(rEntry.nField), nRow)))
+ {
+ bOk = TRUE;
+ }
+ else if (!rEntry.bQueryByString &&
+ (rEntry.eOp == SC_GREATER || rEntry.eOp == SC_GREATER_EQUAL) &&
+ (pCell ? pCell->HasStringData() :
+ HasStringData( static_cast<SCCOL>(rEntry.nField), nRow)))
+ {
+ bOk = TRUE;
+ }
+ }
+
+ if (nPos == -1)
+ {
+ nPos++;
+ pPasst[nPos] = bOk;
+ pTest[nPos] = bTestEqual;
+ }
+ else
+ {
+ if (rEntry.eConnect == SC_AND)
+ {
+ pPasst[nPos] = pPasst[nPos] && bOk;
+ pTest[nPos] = pTest[nPos] && bTestEqual;
+ }
+ else
+ {
+ nPos++;
+ pPasst[nPos] = bOk;
+ pTest[nPos] = bTestEqual;
+ }
+ }
+ i++;
+ }
+
+ for ( long j=1; j <= nPos; j++ )
+ {
+ pPasst[0] = pPasst[0] || pPasst[j];
+ pTest[0] = pTest[0] || pTest[j];
+ }
+
+ BOOL bRet = pPasst[0];
+ if ( pPasst != &aBool[0] )
+ delete [] pPasst;
+ if ( pbTestEqualCondition )
+ *pbTestEqualCondition = pTest[0];
+ if ( pTest != &aTest[0] )
+ delete [] pTest;
+
+ return bRet;
+}
+
+void ScTable::TopTenQuery( ScQueryParam& rParam )
+{
+ BOOL bSortCollatorInitialized = FALSE;
+ SCSIZE nEntryCount = rParam.GetEntryCount();
+ SCROW nRow1 = (rParam.bHasHeader ? rParam.nRow1 + 1 : rParam.nRow1);
+ SCSIZE nCount = static_cast<SCSIZE>(rParam.nRow2 - nRow1 + 1);
+ for ( SCSIZE i=0; (i<nEntryCount) && (rParam.GetEntry(i).bDoQuery); i++ )
+ {
+ ScQueryEntry& rEntry = rParam.GetEntry(i);
+ switch ( rEntry.eOp )
+ {
+ case SC_TOPVAL:
+ case SC_BOTVAL:
+ case SC_TOPPERC:
+ case SC_BOTPERC:
+ {
+ ScSortParam aLocalSortParam( rParam, static_cast<SCCOL>(rEntry.nField) );
+ aSortParam = aLocalSortParam; // used in CreateSortInfoArray, Compare
+ if ( !bSortCollatorInitialized )
+ {
+ bSortCollatorInitialized = TRUE;
+ InitSortCollator( aLocalSortParam );
+ }
+ ScSortInfoArray* pArray = CreateSortInfoArray( nRow1, rParam.nRow2 );
+ DecoladeRow( pArray, nRow1, rParam.nRow2 );
+ QuickSort( pArray, nRow1, rParam.nRow2 );
+ ScSortInfo** ppInfo = pArray->GetFirstArray();
+ SCSIZE nValidCount = nCount;
+ // keine Note-/Leerzellen zaehlen, sind ans Ende sortiert
+ while ( nValidCount > 0 && ( ppInfo[nValidCount-1]->pCell == NULL ||
+ ppInfo[nValidCount-1]->pCell->GetCellType() == CELLTYPE_NOTE ) )
+ nValidCount--;
+ // keine Strings zaehlen, sind zwischen Value und Leer
+ while ( nValidCount > 0
+ && ppInfo[nValidCount-1]->pCell->HasStringData() )
+ nValidCount--;
+ if ( nValidCount > 0 )
+ {
+ if ( rEntry.bQueryByString )
+ { // dat wird nix
+ rEntry.bQueryByString = FALSE;
+ rEntry.nVal = 10; // 10 bzw. 10%
+ }
+ SCSIZE nVal = (rEntry.nVal >= 1 ? static_cast<SCSIZE>(rEntry.nVal) : 1);
+ SCSIZE nOffset = 0;
+ switch ( rEntry.eOp )
+ {
+ case SC_TOPVAL:
+ {
+ rEntry.eOp = SC_GREATER_EQUAL;
+ if ( nVal > nValidCount )
+ nVal = nValidCount;
+ nOffset = nValidCount - nVal; // 1 <= nVal <= nValidCount
+ }
+ break;
+ case SC_BOTVAL:
+ {
+ rEntry.eOp = SC_LESS_EQUAL;
+ if ( nVal > nValidCount )
+ nVal = nValidCount;
+ nOffset = nVal - 1; // 1 <= nVal <= nValidCount
+ }
+ break;
+ case SC_TOPPERC:
+ {
+ rEntry.eOp = SC_GREATER_EQUAL;
+ if ( nVal > 100 )
+ nVal = 100;
+ nOffset = nValidCount - (nValidCount * nVal / 100);
+ if ( nOffset >= nValidCount )
+ nOffset = nValidCount - 1;
+ }
+ break;
+ case SC_BOTPERC:
+ {
+ rEntry.eOp = SC_LESS_EQUAL;
+ if ( nVal > 100 )
+ nVal = 100;
+ nOffset = (nValidCount * nVal / 100);
+ if ( nOffset >= nValidCount )
+ nOffset = nValidCount - 1;
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ ScBaseCell* pCell = ppInfo[nOffset]->pCell;
+ if ( pCell->HasValueData() )
+ {
+ if ( pCell->GetCellType() == CELLTYPE_VALUE )
+ rEntry.nVal = ((ScValueCell*)pCell)->GetValue();
+ else
+ rEntry.nVal = ((ScFormulaCell*)pCell)->GetValue();
+ }
+ else
+ {
+ DBG_ERRORFILE( "TopTenQuery: pCell kein ValueData" );
+ rEntry.eOp = SC_GREATER_EQUAL;
+ rEntry.nVal = 0;
+ }
+ }
+ else
+ {
+ rEntry.eOp = SC_GREATER_EQUAL;
+ rEntry.bQueryByString = FALSE;
+ rEntry.nVal = 0;
+ }
+ delete pArray;
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ if ( bSortCollatorInitialized )
+ DestroySortCollator();
+}
+
+static void lcl_PrepareQuery( ScDocument* pDoc, ScTable* pTab, ScQueryParam& rParam, BOOL* pSpecial )
+{
+ bool bTopTen = false;
+ SCSIZE nEntryCount = rParam.GetEntryCount();
+
+ for ( SCSIZE i = 0; i < nEntryCount; ++i )
+ {
+ pSpecial[i] = FALSE;
+ ScQueryEntry& rEntry = rParam.GetEntry(i);
+ if ( rEntry.bDoQuery )
+ {
+ if ( rEntry.bQueryByString )
+ {
+ sal_uInt32 nIndex = 0;
+ rEntry.bQueryByString = !( pDoc->GetFormatTable()->
+ IsNumberFormat( *rEntry.pStr, nIndex, rEntry.nVal ) );
+ }
+ else
+ {
+ // #58736# call from UNO or second call from autofilter
+ if ( rEntry.nVal == SC_EMPTYFIELDS || rEntry.nVal == SC_NONEMPTYFIELDS )
+ {
+ pSpecial[i] = TRUE;
+ }
+ }
+ if ( !bTopTen )
+ {
+ switch ( rEntry.eOp )
+ {
+ case SC_TOPVAL:
+ case SC_BOTVAL:
+ case SC_TOPPERC:
+ case SC_BOTPERC:
+ {
+ bTopTen = true;
+ }
+ break;
+ default:
+ {
+ }
+ }
+ }
+ }
+ }
+
+ if ( bTopTen )
+ {
+ pTab->TopTenQuery( rParam );
+ }
+}
+
+SCSIZE ScTable::Query(ScQueryParam& rParamOrg, BOOL bKeepSub)
+{
+ ScQueryParam aParam( rParamOrg );
+ ScStrCollection aScStrCollection;
+ StrData* pStrData = NULL;
+
+ BOOL bStarted = FALSE;
+ BOOL bOldResult = TRUE;
+ SCROW nOldStart = 0;
+ SCROW nOldEnd = 0;
+
+ SCSIZE nCount = 0;
+ SCROW nOutRow = 0;
+ SCROW nHeader = aParam.bHasHeader ? 1 : 0;
+
+ SCSIZE nEntryCount = aParam.GetEntryCount();
+ BOOL* pSpecial = new BOOL[nEntryCount];
+ lcl_PrepareQuery( pDocument, this, aParam, pSpecial );
+
+ if (!aParam.bInplace)
+ {
+ nOutRow = aParam.nDestRow + nHeader;
+ if (nHeader > 0)
+ CopyData( aParam.nCol1, aParam.nRow1, aParam.nCol2, aParam.nRow1,
+ aParam.nDestCol, aParam.nDestRow, aParam.nDestTab );
+ }
+
+ for (SCROW j=aParam.nRow1 + nHeader; j<=aParam.nRow2; j++)
+ {
+ BOOL bResult; // Filterergebnis
+ BOOL bValid = ValidQuery(j, aParam, pSpecial);
+ if (!bValid && bKeepSub) // Subtotals stehenlassen
+ {
+ for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++)
+ {
+ ScBaseCell* pCell;
+ pCell = GetCell( nCol, j );
+ if ( pCell )
+ if ( pCell->GetCellType() == CELLTYPE_FORMULA )
+ if (((ScFormulaCell*)pCell)->IsSubTotal())
+ if (RefVisible((ScFormulaCell*)pCell))
+ bValid = TRUE;
+ }
+ }
+ if (bValid)
+ {
+ if (aParam.bDuplicate)
+ bResult = TRUE;
+ else
+ {
+ String aStr;
+ for (SCCOL k=aParam.nCol1; k <= aParam.nCol2; k++)
+ {
+ String aCellStr;
+ GetString(k, j, aCellStr);
+ aStr += aCellStr;
+ aStr += (sal_Unicode)1;
+ }
+ pStrData = new StrData(aStr);
+
+ BOOL bIsUnique = TRUE;
+ if (pStrData)
+ bIsUnique = aScStrCollection.Insert(pStrData);
+ if (bIsUnique)
+ bResult = TRUE;
+ else
+ {
+ delete pStrData;
+ bResult = FALSE;
+ }
+ }
+ }
+ else
+ bResult = FALSE;
+
+ if (aParam.bInplace)
+ {
+ if (bResult == bOldResult && bStarted)
+ nOldEnd = j;
+ else
+ {
+ if (bStarted)
+ DBShowRows(nOldStart,nOldEnd, bOldResult);
+ nOldStart = nOldEnd = j;
+ bOldResult = bResult;
+ }
+ bStarted = TRUE;
+ }
+ else
+ {
+ if (bResult)
+ {
+ CopyData( aParam.nCol1,j, aParam.nCol2,j, aParam.nDestCol,nOutRow,aParam.nDestTab );
+ ++nOutRow;
+ }
+ }
+ if (bResult)
+ ++nCount;
+ }
+
+ if (aParam.bInplace && bStarted)
+ DBShowRows(nOldStart,nOldEnd, bOldResult);
+
+ delete[] pSpecial;
+
+ return nCount;
+}
+
+BOOL ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
+{
+ BOOL bValid = TRUE;
+ SCCOL* pFields = new SCCOL[nCol2-nCol1+1];
+ String aCellStr;
+ SCCOL nCol = nCol1;
+ DBG_ASSERT( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
+ SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
+ SCROW nDBRow1 = rQueryParam.nRow1;
+ SCCOL nDBCol2 = rQueryParam.nCol2;
+ // Erste Zeile muessen Spaltenkoepfe sein
+ while (bValid && (nCol <= nCol2))
+ {
+ String aQueryStr;
+ GetUpperCellString(nCol, nRow1, aQueryStr);
+ BOOL bFound = FALSE;
+ SCCOL i = rQueryParam.nCol1;
+ while (!bFound && (i <= nDBCol2))
+ {
+ if ( nTab == nDBTab )
+ GetUpperCellString(i, nDBRow1, aCellStr);
+ else
+ pDocument->GetUpperCellString(i, nDBRow1, nDBTab, aCellStr);
+ bFound = (aCellStr == aQueryStr);
+ if (!bFound) i++;
+ }
+ if (bFound)
+ pFields[nCol - nCol1] = i;
+ else
+ bValid = FALSE;
+ nCol++;
+ }
+ if (bValid)
+ {
+ ULONG nVisible = 0;
+ for ( nCol=nCol1; nCol<=nCol2; nCol++ )
+ nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 );
+
+ if ( nVisible > SCSIZE_MAX / sizeof(void*) )
+ {
+ DBG_ERROR("zu viele Filterkritierien");
+ nVisible = 0;
+ }
+
+ SCSIZE nNewEntries = nVisible;
+ rQueryParam.Resize( nNewEntries );
+
+ SCSIZE nIndex = 0;
+ SCROW nRow = nRow1 + 1;
+ while (nRow <= nRow2)
+ {
+ nCol = nCol1;
+ while (nCol <= nCol2)
+ {
+ GetInputString( nCol, nRow, aCellStr );
+ ScGlobal::pCharClass->toUpper( aCellStr );
+ if (aCellStr.Len() > 0)
+ {
+ if (nIndex < nNewEntries)
+ {
+ rQueryParam.GetEntry(nIndex).nField = pFields[nCol - nCol1];
+ rQueryParam.FillInExcelSyntax(aCellStr, nIndex);
+ nIndex++;
+ if (nIndex < nNewEntries)
+ rQueryParam.GetEntry(nIndex).eConnect = SC_AND;
+ }
+ else
+ bValid = FALSE;
+ }
+ nCol++;
+ }
+ nRow++;
+ if (nIndex < nNewEntries)
+ rQueryParam.GetEntry(nIndex).eConnect = SC_OR;
+ }
+ }
+ delete [] pFields;
+ return bValid;
+}
+
+BOOL ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
+{
+ // A valid StarQuery must be at least 4 columns wide. To be precise it
+ // should be exactly 4 columns ...
+ // Additionally, if this wasn't checked, a formula pointing to a valid 1-3
+ // column Excel style query range immediately left to itself would result
+ // in a circular reference when the field name or operator or value (first
+ // to third query range column) is obtained (#i58354#). Furthermore, if the
+ // range wasn't sufficiently specified data changes wouldn't flag formula
+ // cells for recalculation.
+ if (nCol2 - nCol1 < 3)
+ return FALSE;
+
+ BOOL bValid;
+ BOOL bFound;
+ String aCellStr;
+ SCSIZE nIndex = 0;
+ SCROW nRow = nRow1;
+ DBG_ASSERT( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
+ SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
+ SCROW nDBRow1 = rQueryParam.nRow1;
+ SCCOL nDBCol2 = rQueryParam.nCol2;
+
+ SCSIZE nNewEntries = static_cast<SCSIZE>(nRow2-nRow1+1);
+ rQueryParam.Resize( nNewEntries );
+
+ do
+ {
+ ScQueryEntry& rEntry = rQueryParam.GetEntry(nIndex);
+
+ bValid = FALSE;
+ // Erste Spalte UND/ODER
+ if (nIndex > 0)
+ {
+ GetUpperCellString(nCol1, nRow, aCellStr);
+ if ( aCellStr == ScGlobal::GetRscString(STR_TABLE_UND) )
+ {
+ rEntry.eConnect = SC_AND;
+ bValid = TRUE;
+ }
+ else if ( aCellStr == ScGlobal::GetRscString(STR_TABLE_ODER) )
+ {
+ rEntry.eConnect = SC_OR;
+ bValid = TRUE;
+ }
+ }
+ // Zweite Spalte FeldName
+ if ((nIndex < 1) || bValid)
+ {
+ bFound = FALSE;
+ GetUpperCellString(nCol1 + 1, nRow, aCellStr);
+ for (SCCOL i=rQueryParam.nCol1; (i <= nDBCol2) && (!bFound); i++)
+ {
+ String aFieldStr;
+ if ( nTab == nDBTab )
+ GetUpperCellString(i, nDBRow1, aFieldStr);
+ else
+ pDocument->GetUpperCellString(i, nDBRow1, nDBTab, aFieldStr);
+ bFound = (aCellStr == aFieldStr);
+ if (bFound)
+ {
+ rEntry.nField = i;
+ bValid = TRUE;
+ }
+ else
+ bValid = FALSE;
+ }
+ }
+ // Dritte Spalte Operator =<>...
+ if (bValid)
+ {
+ bFound = FALSE;
+ GetUpperCellString(nCol1 + 2, nRow, aCellStr);
+ if (aCellStr.GetChar(0) == '<')
+ {
+ if (aCellStr.GetChar(1) == '>')
+ rEntry.eOp = SC_NOT_EQUAL;
+ else if (aCellStr.GetChar(1) == '=')
+ rEntry.eOp = SC_LESS_EQUAL;
+ else
+ rEntry.eOp = SC_LESS;
+ }
+ else if (aCellStr.GetChar(0) == '>')
+ {
+ if (aCellStr.GetChar(1) == '=')
+ rEntry.eOp = SC_GREATER_EQUAL;
+ else
+ rEntry.eOp = SC_GREATER;
+ }
+ else if (aCellStr.GetChar(0) == '=')
+ rEntry.eOp = SC_EQUAL;
+
+ }
+ // Vierte Spalte Wert
+ if (bValid)
+ {
+ GetString(nCol1 + 3, nRow, *rEntry.pStr);
+ rEntry.bDoQuery = TRUE;
+ }
+ nIndex++;
+ nRow++;
+ }
+ while (bValid && (nRow <= nRow2) /* && (nIndex < MAXQUERY) */ );
+ return bValid;
+}
+
+BOOL ScTable::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
+{
+ SCSIZE i, nCount;
+ PutInOrder(nCol1, nCol2);
+ PutInOrder(nRow1, nRow2);
+
+ nCount = rQueryParam.GetEntryCount();
+ for (i=0; i < nCount; i++)
+ rQueryParam.GetEntry(i).Clear();
+
+ // Standard QueryTabelle
+ BOOL bValid = CreateStarQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
+ // Excel QueryTabelle
+ if (!bValid)
+ bValid = CreateExcelQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
+
+ nCount = rQueryParam.GetEntryCount();
+ if (bValid)
+ {
+ // bQueryByString muss gesetzt sein
+ for (i=0; i < nCount; i++)
+ rQueryParam.GetEntry(i).bQueryByString = TRUE;
+ }
+ else
+ {
+ // nix
+ for (i=0; i < nCount; i++)
+ rQueryParam.GetEntry(i).Clear();
+ }
+ return bValid;
+}
+
+BOOL ScTable::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW /* nEndRow */ )
+{
+ for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
+ {
+ CellType eType = GetCellType( nCol, nStartRow );
+ if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOL ScTable::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL /* nEndCol */, SCROW nEndRow )
+{
+ for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
+ {
+ CellType eType = GetCellType( nStartCol, nRow );
+ if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void ScTable::GetFilterEntries(SCCOL nCol, SCROW nRow1, SCROW nRow2, TypedScStrCollection& rStrings)
+{
+ aCol[nCol].GetFilterEntries( nRow1, nRow2, rStrings );
+}
+
+void ScTable::GetFilteredFilterEntries( SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam& rParam, TypedScStrCollection& rStrings )
+{
+ // remove the entry for this column from the query parameter
+ ScQueryParam aParam( rParam );
+ SCSIZE nEntryCount = aParam.GetEntryCount();
+ for ( SCSIZE i = 0; i < nEntryCount && aParam.GetEntry(i).bDoQuery; ++i )
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if ( rEntry.nField == nCol )
+ {
+ aParam.DeleteQuery(i);
+ break;
+ }
+ }
+ nEntryCount = aParam.GetEntryCount();
+
+ BOOL* pSpecial = new BOOL[nEntryCount];
+ lcl_PrepareQuery( pDocument, this, aParam, pSpecial );
+
+ for ( SCROW j = nRow1; j <= nRow2; ++j )
+ {
+ if ( ValidQuery( j, aParam, pSpecial ) )
+ {
+ aCol[nCol].GetFilterEntries( j, j, rStrings );
+ }
+ }
+
+ delete[] pSpecial;
+}
+
+BOOL ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, TypedScStrCollection& rStrings, BOOL bLimit)
+{
+ return aCol[nCol].GetDataEntries( nRow, rStrings, bLimit );
+}
+
+ULONG ScTable::GetCellCount() const
+{
+ ULONG nCellCount = 0;
+
+ for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
+ nCellCount += aCol[nCol].GetCellCount();
+
+ return nCellCount;
+}
+
+ULONG ScTable::GetWeightedCount() const
+{
+ ULONG nCellCount = 0;
+
+ for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
+ if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline
+ nCellCount += aCol[nCol].GetWeightedCount();
+
+ return nCellCount;
+}
+
+ULONG ScTable::GetCodeCount() const
+{
+ ULONG nCodeCount = 0;
+
+ for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
+ if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline
+ nCodeCount += aCol[nCol].GetCodeCount();
+
+ return nCodeCount;
+}
+
+sal_Int32 ScTable::GetMaxStringLen( SCCOL nCol, SCROW nRowStart,
+ SCROW nRowEnd, CharSet eCharSet ) const
+{
+ if ( ValidCol(nCol) )
+ return aCol[nCol].GetMaxStringLen( nRowStart, nRowEnd, eCharSet );
+ else
+ return 0;
+}
+
+xub_StrLen ScTable::GetMaxNumberStringLen( USHORT& nPrecision, SCCOL nCol,
+ SCROW nRowStart, SCROW nRowEnd ) const
+{
+ if ( ValidCol(nCol) )
+ return aCol[nCol].GetMaxNumberStringLen( nPrecision, nRowStart, nRowEnd );
+ else
+ return 0;
+}
+
+void ScTable::UpdateSelectionFunction( ScFunctionData& rData,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark )
+{
+ // Cursor neben einer Markierung nicht beruecksichtigen:
+ //! nur noch MarkData uebergeben, Cursorposition ggf. hineinselektieren!!!
+ BOOL bSingle = ( rMark.IsMarked() || !rMark.IsMultiMarked() );
+
+ // Mehrfachselektion:
+
+ SCCOL nCol;
+ if ( rMark.IsMultiMarked() )
+ for (nCol=0; nCol<=MAXCOL && !rData.bError; nCol++)
+ if ( !pColFlags || !( pColFlags[nCol] & CR_HIDDEN ) )
+ aCol[nCol].UpdateSelectionFunction( rMark, rData, pRowFlags,
+ bSingle && ( nCol >= nStartCol && nCol <= nEndCol ),
+ nStartRow, nEndRow );
+
+ // Einfachselektion (oder Cursor) nur wenn nicht negativ (und s.o.):
+
+ if ( bSingle && !rMark.IsMarkNegative() )
+ for (nCol=nStartCol; nCol<=nEndCol && !rData.bError; nCol++)
+ if ( !pColFlags || !( pColFlags[nCol] & CR_HIDDEN ) )
+ aCol[nCol].UpdateAreaFunction( rData, pRowFlags, nStartRow, nEndRow );
+}
+
+void ScTable::FindConditionalFormat( ULONG nKey, ScRangeList& rList )
+{
+ SCROW nStartRow = 0, nEndRow = 0;
+ for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
+ {
+ ScAttrIterator* pIter = aCol[nCol].CreateAttrIterator( 0, MAXROW );
+ const ScPatternAttr* pPattern = pIter->Next( nStartRow, nEndRow );
+ while (pPattern)
+ {
+ if (((SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() == nKey)
+ rList.Join( ScRange(nCol,nStartRow,nTab, nCol,nEndRow,nTab) );
+ pPattern = pIter->Next( nStartRow, nEndRow );
+ }
+ delete pIter;
+ }
+}
+
+
+
+
diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
new file mode 100644
index 000000000000..a29a34ebd7e3
--- /dev/null
+++ b/sc/source/core/data/table4.cxx
@@ -0,0 +1,1986 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: table4.cxx,v $
+ * $Revision: 1.23.126.4 $
+ *
+ * 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"
+
+// System - Includes -----------------------------------------------------
+
+
+
+#ifdef _MSC_VER
+#pragma optimize("",off)
+ // sonst Absturz Win beim Fuellen
+#endif
+
+// INCLUDE ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <svx/algitem.hxx>
+#include <svx/boxitem.hxx>
+#include <svx/brshitem.hxx>
+#include <svx/cntritem.hxx>
+#include <svx/colritem.hxx>
+#include <svx/crsditem.hxx>
+#include <svx/fhgtitem.hxx>
+#include <svx/fontitem.hxx>
+#include <svx/langitem.hxx>
+#include <svx/postitem.hxx>
+#include <svx/shdditem.hxx>
+#include <svx/udlnitem.hxx>
+#include <svx/wghtitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <svx/editobj.hxx>
+#include <svx/editeng.hxx>
+#include <svx/eeitem.hxx>
+#include <svx/escpitem.hxx>
+#include <svtools/zforlist.hxx>
+#include <vcl/keycodes.hxx>
+#include <rtl/math.hxx>
+#include <unotools/charclass.hxx>
+
+#include "attrib.hxx"
+#include "patattr.hxx"
+#include "cell.hxx"
+#include "table.hxx"
+#include "globstr.hrc"
+#include "global.hxx"
+#include "document.hxx"
+#include "autoform.hxx"
+#include "userlist.hxx"
+#include "zforauto.hxx"
+#include "subtotal.hxx"
+#include "formula/errorcodes.hxx"
+#include "rangenam.hxx"
+#include "docpool.hxx"
+#include "progress.hxx"
+
+#include <math.h>
+
+// STATIC DATA -----------------------------------------------------------
+
+#define _D_MAX_LONG_ (double) 0x7fffffff
+
+extern USHORT nScFillModeMouseModifier; // global.cxx
+
+// -----------------------------------------------------------------------
+
+short lcl_DecompValueString( String& aValue, sal_Int32& nVal, USHORT* pMinDigits = NULL )
+{
+ if ( !aValue.Len() )
+ {
+ nVal = 0;
+ return 0;
+ }
+ const sal_Unicode* p = aValue.GetBuffer();
+ xub_StrLen nNeg = 0;
+ xub_StrLen nNum = 0;
+ if ( p[nNum] == '-' )
+ nNum = nNeg = 1;
+ while ( p[nNum] && CharClass::isAsciiNumeric( p[nNum] ) )
+ nNum++;
+ if ( nNum > nNeg )
+ { // number at the beginning
+ nVal = aValue.Copy( 0, nNum ).ToInt32();
+ // #60893# any number with a leading zero sets the minimum number of digits
+ if ( p[nNeg] == '0' && pMinDigits && ( nNum - nNeg > *pMinDigits ) )
+ *pMinDigits = nNum - nNeg;
+ aValue.Erase( 0, nNum );
+ return -1;
+ }
+ else
+ {
+ nNeg = 0;
+ xub_StrLen nEnd = nNum = aValue.Len() - 1;
+ while ( nNum && CharClass::isAsciiNumeric( p[nNum] ) )
+ nNum--;
+ if ( p[nNum] == '-' )
+ {
+ nNum--;
+ nNeg = 1;
+ }
+ if ( nNum < nEnd - nNeg )
+ { // number at the end
+ nVal = aValue.Copy( nNum + 1 ).ToInt32();
+ // #60893# any number with a leading zero sets the minimum number of digits
+ if ( p[nNum+1+nNeg] == '0' && pMinDigits && ( nEnd - nNum - nNeg > *pMinDigits ) )
+ *pMinDigits = nEnd - nNum - nNeg;
+ aValue.Erase( nNum + 1 );
+ return 1;
+ }
+ }
+ nVal = 0;
+ return 0;
+}
+
+String lcl_ValueString( sal_Int32 nValue, USHORT nMinDigits )
+{
+ if ( nMinDigits <= 1 )
+ return String::CreateFromInt32( nValue ); // simple case...
+ else
+ {
+ String aStr = String::CreateFromInt32( Abs( nValue ) );
+ if ( aStr.Len() < nMinDigits )
+ {
+ String aZero;
+ aZero.Fill( nMinDigits - aStr.Len(), '0' );
+ aStr.Insert( aZero, 0 );
+ }
+ // nMinDigits doesn't include the '-' sign -> add after inserting zeros
+ if ( nValue < 0 )
+ aStr.Insert( '-', 0 );
+ return aStr;
+ }
+}
+
+static ScBaseCell * lcl_getSuffixCell( ScDocument* pDocument, sal_Int32 nValue,
+ USHORT nDigits, const String& rSuffix, CellType eCellType,
+ BOOL bIsOrdinalSuffix )
+{
+ String aValue( lcl_ValueString( nValue, nDigits ));
+ if (!bIsOrdinalSuffix)
+ return new ScStringCell( aValue += rSuffix);
+
+ String aOrdinalSuffix( ScGlobal::GetOrdinalSuffix( nValue));
+ if (eCellType != CELLTYPE_EDIT)
+ return new ScStringCell( aValue += aOrdinalSuffix);
+
+ EditEngine aEngine( pDocument->GetEnginePool() );
+ SfxItemSet aAttr = aEngine.GetEmptyItemSet();
+ aAttr.Put( SvxEscapementItem( SVX_ESCAPEMENT_SUPERSCRIPT, EE_CHAR_ESCAPEMENT));
+ aEngine.SetText( aValue );
+ aEngine.QuickInsertText( aOrdinalSuffix, ESelection( 0, aValue.Len(), 0,
+ aValue.Len() + aOrdinalSuffix.Len()));
+ aEngine.QuickSetAttribs( aAttr, ESelection( 0, aValue.Len(), 0, aValue.Len() +
+ aOrdinalSuffix.Len()));
+ return new ScEditCell( aEngine.CreateTextObject(), pDocument, NULL );
+}
+
+void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ FillCmd& rCmd, FillDateCmd& rDateCmd,
+ double& rInc, USHORT& rMinDigits,
+ ScUserListData*& rListData, USHORT& rListIndex)
+{
+ DBG_ASSERT( nCol1==nCol2 || nRow1==nRow2, "FillAnalyse: falscher Bereich" );
+
+ rInc = 0.0;
+ rMinDigits = 0;
+ rListData = NULL;
+ rCmd = FILL_SIMPLE;
+ if ( nScFillModeMouseModifier & KEY_MOD1 )
+ return ; // Ctrl-Taste: Copy
+
+ SCCOL nAddX;
+ SCROW nAddY;
+ SCSIZE nCount;
+ if (nCol1 == nCol2)
+ {
+ nAddX = 0;
+ nAddY = 1;
+ nCount = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
+ }
+ else
+ {
+ nAddX = 1;
+ nAddY = 0;
+ nCount = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
+ }
+
+ SCCOL nCol = nCol1;
+ SCROW nRow = nRow1;
+
+ ScBaseCell* pFirstCell = GetCell( nCol, nRow );
+ CellType eCellType = pFirstCell ? pFirstCell->GetCellType() : CELLTYPE_NONE;
+
+ if (eCellType == CELLTYPE_VALUE)
+ {
+ UINT32 nFormat = ((const SfxUInt32Item*)GetAttr(nCol,nRow,ATTR_VALUE_FORMAT))->GetValue();
+ BOOL bDate = ( pDocument->GetFormatTable()->GetType(nFormat) == NUMBERFORMAT_DATE );
+ if (bDate)
+ {
+ if (nCount > 1)
+ {
+ long nCmpInc = 0;
+ double nVal;
+ Date aNullDate = *pDocument->GetFormatTable()->GetNullDate();
+ Date aDate1 = aNullDate;
+ nVal = ((ScValueCell*)pFirstCell)->GetValue();
+ aDate1 += (long)nVal;
+ Date aDate2 = aNullDate;
+ nVal = GetValue(nCol+nAddX, nRow+nAddY);
+ aDate2 += (long)nVal;
+ if ( aDate1 != aDate2 )
+ {
+ FillDateCmd eType;
+ long nDDiff = aDate2.GetDay() - (long) aDate1.GetDay();
+ long nMDiff = aDate2.GetMonth() - (long) aDate1.GetMonth();
+ long nYDiff = aDate2.GetYear() - (long) aDate1.GetYear();
+ if ( nDDiff )
+ {
+ eType = FILL_DAY;
+ nCmpInc = aDate2 - aDate1;
+ }
+ else
+ {
+ eType = FILL_MONTH;
+ nCmpInc = nMDiff + 12 * nYDiff;
+ }
+
+ nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
+ nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ BOOL bVal = TRUE;
+ for (USHORT i=1; i<nCount && bVal; i++)
+ {
+ ScBaseCell* pCell = GetCell(nCol,nRow);
+ if (pCell && pCell->GetCellType() == CELLTYPE_VALUE)
+ {
+ nVal = ((ScValueCell*)pCell)->GetValue();
+ aDate2 = aNullDate + (long) nVal;
+ if ( eType == FILL_DAY )
+ {
+ if ( aDate2-aDate1 != nCmpInc )
+ bVal = FALSE;
+ }
+ else
+ {
+ nDDiff = aDate2.GetDay() - (long) aDate1.GetDay();
+ nMDiff = aDate2.GetMonth() - (long) aDate1.GetMonth();
+ nYDiff = aDate2.GetYear() - (long) aDate1.GetYear();
+ if (nDDiff || ( nMDiff + 12 * nYDiff != nCmpInc ))
+ bVal = FALSE;
+ }
+ aDate1 = aDate2;
+ nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
+ nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ }
+ else
+ bVal = FALSE; // #50965# kein Datum passt auch nicht
+ }
+ if (bVal)
+ {
+ if ( eType == FILL_MONTH && ( nCmpInc % 12 == 0 ) )
+ {
+ eType = FILL_YEAR;
+ nCmpInc /= 12;
+ }
+ rCmd = FILL_DATE;
+ rDateCmd = eType;
+ rInc = nCmpInc;
+ }
+ }
+ }
+ else // einzelnes Datum -> Tage hochzaehlen
+ {
+ rCmd = FILL_DATE;
+ rDateCmd = FILL_DAY;
+ rInc = 1.0;
+ }
+ }
+ else
+ {
+ if (nCount > 1)
+ {
+ double nVal1 = ((ScValueCell*)pFirstCell)->GetValue();
+ double nVal2 = GetValue(nCol+nAddX, nRow+nAddY);
+ rInc = nVal2 - nVal1;
+ nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
+ nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ BOOL bVal = TRUE;
+ for (USHORT i=1; i<nCount && bVal; i++)
+ {
+ ScBaseCell* pCell = GetCell(nCol,nRow);
+ if (pCell && pCell->GetCellType() == CELLTYPE_VALUE)
+ {
+ nVal2 = ((ScValueCell*)pCell)->GetValue();
+ double nDiff = nVal2 - nVal1;
+ if ( !::rtl::math::approxEqual( nDiff, rInc ) )
+ bVal = FALSE;
+ nVal1 = nVal2;
+ }
+ else
+ bVal = FALSE;
+ nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
+ nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ }
+ if (bVal)
+ rCmd = FILL_LINEAR;
+ }
+ }
+ }
+ else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
+ {
+ String aStr;
+ GetString(nCol, nRow, aStr);
+ rListData = (ScUserListData*)(ScGlobal::GetUserList()->GetData(aStr));
+ if (rListData)
+ {
+ rListData->GetSubIndex(aStr, rListIndex);
+ nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
+ nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ for (USHORT i=1; i<nCount && rListData; i++)
+ {
+ GetString(nCol, nRow, aStr);
+ if (!rListData->GetSubIndex(aStr, rListIndex))
+ rListData = NULL;
+ nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
+ nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ }
+ }
+ else if ( nCount > 1 )
+ {
+ // pass rMinDigits to all DecompValueString calls
+ // -> longest number defines rMinDigits
+
+ sal_Int32 nVal1;
+ short nFlag1 = lcl_DecompValueString( aStr, nVal1, &rMinDigits );
+ if ( nFlag1 )
+ {
+ sal_Int32 nVal2;
+ GetString( nCol+nAddX, nRow+nAddY, aStr );
+ short nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
+ if ( nFlag1 == nFlag2 )
+ {
+ rInc = (double)nVal2 - (double)nVal1;
+ nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
+ nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ BOOL bVal = TRUE;
+ for (USHORT i=1; i<nCount && bVal; i++)
+ {
+ ScBaseCell* pCell = GetCell(nCol,nRow);
+ CellType eType = pCell ? pCell->GetCellType() : CELLTYPE_NONE;
+ if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
+ {
+ if ( eType == CELLTYPE_STRING )
+ ((ScStringCell*)pCell)->GetString( aStr );
+ else
+ ((ScEditCell*)pCell)->GetString( aStr );
+ nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
+ if ( nFlag1 == nFlag2 )
+ {
+ double nDiff = (double)nVal2 - (double)nVal1;
+ if ( !::rtl::math::approxEqual( nDiff, rInc ) )
+ bVal = FALSE;
+ nVal1 = nVal2;
+ }
+ else
+ bVal = FALSE;
+ }
+ else
+ bVal = FALSE;
+ nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
+ nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
+ }
+ if (bVal)
+ rCmd = FILL_LINEAR;
+ }
+ }
+ }
+ else
+ {
+ // call DecompValueString to set rMinDigits
+ sal_Int32 nDummy;
+ lcl_DecompValueString( aStr, nDummy, &rMinDigits );
+ }
+ }
+}
+
+void ScTable::FillFormula(ULONG& /* nFormulaCounter */, BOOL /* bFirst */, ScFormulaCell* pSrcCell,
+ SCCOL nDestCol, SCROW nDestRow, BOOL bLast )
+{
+/* USHORT nTokArrLen = pSrcCell->GetTokenArrayLen();
+ if ( nTokArrLen > 15 ) // mehr als =A1 oder =67
+ {
+ ScRangeName* pRangeName = pDocument->GetRangeName();
+ String aName("___SC_"); // Wird dieser String veraendert,
+ // auch in document2 EraseNonUsed...
+ // mitaendern!!
+ aName += pRangeName->GetSharedMaxIndex() + 1;
+ aName += '_';
+ aName += nFormulaCounter;
+ nFormulaCounter++;
+ if (bFirst)
+ {
+ ScRangeData *pAktRange = new ScRangeData(
+ pDocument, aName, pSrcCell->GetTokenArray(), nTokArrLen,
+ pSrcCell->GetCol(), pSrcCell->GetRow(), nTab ,RT_SHARED);
+ if (!pRangeName->Insert( pAktRange ))
+ delete pAktRange;
+ else
+ bSharedNameInserted = TRUE;
+ }
+ USHORT nIndex;
+ pRangeName->SearchName(aName, nIndex);
+ if (!pRangeName)
+ {
+ DBG_ERROR("ScTable::FillFormula: Falscher Name");
+ return;
+ }
+ nIndex = ((ScRangeData*) ((*pRangeName)[nIndex]))->GetIndex();
+ ScTokenArray aArr;
+ aArr.AddName(nIndex);
+ aArr.AddOpCode(ocStop);
+ ScFormulaCell* pDestCell = new ScFormulaCell
+ (pDocument, ScAddress( nDestCol, nDestRow, nTab ), aArr );
+ aCol[nDestCol].Insert(nDestRow, pDestCell);
+ }
+ else
+*/ {
+ pDocument->SetNoListening( TRUE ); // noch falsche Referenzen
+ ScAddress aAddr( nDestCol, nDestRow, nTab );
+ ScFormulaCell* pDestCell = new ScFormulaCell( *pSrcCell, *pDocument, aAddr );
+ aCol[nDestCol].Insert(nDestRow, pDestCell);
+#if 0
+// mit RelRefs unnoetig
+ pDestCell->UpdateReference(URM_COPY,
+ ScRange( aAddr, aAddr ),
+ nDestCol - pSrcCell->aPos.Col(),
+ nDestRow - pSrcCell->aPos.Row(), 0);
+#endif
+ if ( bLast && pDestCell->GetMatrixFlag() )
+ {
+ ScAddress aOrg;
+ if ( pDestCell->GetMatrixOrigin( aOrg ) )
+ {
+ if ( nDestCol >= aOrg.Col() && nDestRow >= aOrg.Row() )
+ {
+ ScBaseCell* pOrgCell = pDocument->GetCell( aOrg );
+ if ( pOrgCell && pOrgCell->GetCellType() == CELLTYPE_FORMULA
+ && ((ScFormulaCell*)pOrgCell)->GetMatrixFlag() == MM_FORMULA )
+ {
+ ((ScFormulaCell*)pOrgCell)->SetMatColsRows(
+ nDestCol - aOrg.Col() + 1,
+ nDestRow - aOrg.Row() + 1 );
+ }
+ else
+ {
+ DBG_ERRORFILE( "FillFormula: MatrixOrigin keine Formelzelle mit MM_FORMULA" );
+ }
+ }
+ else
+ {
+ DBG_ERRORFILE( "FillFormula: MatrixOrigin rechts unten" );
+ }
+ }
+ else
+ {
+ DBG_ERRORFILE( "FillFormula: kein MatrixOrigin" );
+ }
+ }
+ pDocument->SetNoListening( FALSE );
+ pDestCell->StartListeningTo( pDocument );
+ }
+}
+
+void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ ULONG nFillCount, FillDir eFillDir, ScProgress& rProgress )
+{
+ if ( (nFillCount == 0) || !ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2) )
+ return;
+
+ //
+ // Richtung auswerten
+ //
+
+ BOOL bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
+ BOOL bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
+
+ ULONG nCol = 0;
+ ULONG nRow = 0;
+ ULONG& rInner = bVertical ? nRow : nCol; // Schleifenvariablen
+ ULONG& rOuter = bVertical ? nCol : nRow;
+ ULONG nOStart;
+ ULONG nOEnd;
+ ULONG nIStart;
+ ULONG nIEnd;
+ ULONG nISrcStart;
+ ULONG nISrcEnd;
+
+ if (bVertical)
+ {
+ nOStart = nCol1;
+ nOEnd = nCol2;
+ if (bPositive)
+ {
+ nISrcStart = nRow1;
+ nISrcEnd = nRow2;
+ nIStart = nRow2 + 1;
+ nIEnd = nRow2 + nFillCount;
+ }
+ else
+ {
+ nISrcStart = nRow2;
+ nISrcEnd = nRow1;
+ nIStart = nRow1 - 1;
+ nIEnd = nRow1 - nFillCount;
+ }
+ }
+ else
+ {
+ nOStart = nRow1;
+ nOEnd = nRow2;
+ if (bPositive)
+ {
+ nISrcStart = nCol1;
+ nISrcEnd = nCol2;
+ nIStart = nCol2 + 1;
+ nIEnd = nCol2 + nFillCount;
+ }
+ else
+ {
+ nISrcStart = nCol2;
+ nISrcEnd = nCol1;
+ nIStart = nCol1 - 1;
+ nIEnd = nCol1 - nFillCount;
+ }
+ }
+ ULONG nIMin = nIStart;
+ ULONG nIMax = nIEnd;
+ PutInOrder(nIMin,nIMax);
+ if (bVertical)
+ DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), IDF_AUTOFILL);
+ else
+ DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, IDF_AUTOFILL);
+
+ ULONG nProgress = rProgress.GetState();
+
+ //
+ // ausfuehren
+ //
+
+ ULONG nActFormCnt = 0;
+ for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
+ {
+ ULONG nMaxFormCnt = 0; // fuer Formeln
+
+ // Attributierung uebertragen
+
+ const ScPatternAttr* pSrcPattern = NULL;
+ ULONG nAtSrc = nISrcStart;
+ ScPatternAttr* pNewPattern = NULL;
+ BOOL bGetPattern = TRUE;
+ rInner = nIStart;
+ while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
+ {
+ const ScStyleSheet* pStyleSheet = NULL;
+ if ( bGetPattern )
+ {
+ if ( pNewPattern )
+ delete pNewPattern;
+ if (bVertical) // rInner&:=nRow, rOuter&:=nCol
+ pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nAtSrc));
+ else // rInner&:=nCol, rOuter&:=nRow
+ pSrcPattern = aCol[nAtSrc].GetPattern(static_cast<SCROW>(nRow));
+ bGetPattern = FALSE;
+ pStyleSheet = pSrcPattern->GetStyleSheet();
+ // Merge/Mergeflag nicht uebernehmen,
+ const SfxItemSet& rSet = pSrcPattern->GetItemSet();
+ if ( rSet.GetItemState(ATTR_MERGE, FALSE) == SFX_ITEM_SET
+ || rSet.GetItemState(ATTR_MERGE_FLAG, FALSE) == SFX_ITEM_SET )
+ {
+ pNewPattern = new ScPatternAttr( *pSrcPattern );
+ SfxItemSet& rNewSet = pNewPattern->GetItemSet();
+ rNewSet.ClearItem(ATTR_MERGE);
+ rNewSet.ClearItem(ATTR_MERGE_FLAG);
+ }
+ else
+ pNewPattern = NULL;
+ }
+
+ if ( bVertical && nISrcStart == nISrcEnd )
+ {
+ // Attribute komplett am Stueck setzen
+ if (pNewPattern || pSrcPattern != pDocument->GetDefPattern())
+ {
+ // Default steht schon da (DeleteArea)
+ SCROW nY1 = static_cast<SCROW>(Min( nIStart, nIEnd ));
+ SCROW nY2 = static_cast<SCROW>(Max( nIStart, nIEnd ));
+ if ( pStyleSheet )
+ aCol[nCol].ApplyStyleArea( nY1, nY2, *pStyleSheet );
+ if ( pNewPattern )
+ aCol[nCol].ApplyPatternArea( nY1, nY2, *pNewPattern );
+ else
+ aCol[nCol].ApplyPatternArea( nY1, nY2, *pSrcPattern );
+ }
+ break; // Schleife abbrechen
+ }
+
+ if ( pSrcPattern != aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) )
+ {
+ // Vorlage auch uebernehmen
+ //! am AttrArray mit ApplyPattern zusammenfassen ??
+ if ( pStyleSheet )
+ aCol[nCol].ApplyStyle( static_cast<SCROW>(nRow), *pStyleSheet );
+
+ // ApplyPattern statt SetPattern um alte MergeFlags stehenzulassen
+ if ( pNewPattern )
+ aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pNewPattern );
+ else
+ aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pSrcPattern );
+ }
+
+ if (nAtSrc==nISrcEnd)
+ {
+ if ( nAtSrc != nISrcStart )
+ { // mehr als eine Source-Zelle
+ nAtSrc = nISrcStart;
+ bGetPattern = TRUE;
+ }
+ }
+ else if (bPositive)
+ {
+ ++nAtSrc;
+ bGetPattern = TRUE;
+ }
+ else
+ {
+ --nAtSrc;
+ bGetPattern = TRUE;
+ }
+
+ if (rInner == nIEnd) break;
+ if (bPositive) ++rInner; else --rInner;
+ }
+ if ( pNewPattern )
+ delete pNewPattern;
+
+ // Analyse
+
+ FillCmd eFillCmd;
+ FillDateCmd eDateCmd;
+ double nInc;
+ USHORT nMinDigits;
+ ScUserListData* pListData = NULL;
+ USHORT nListIndex;
+ if (bVertical)
+ FillAnalyse(static_cast<SCCOL>(nCol),nRow1,
+ static_cast<SCCOL>(nCol),nRow2, eFillCmd,eDateCmd,
+ nInc,nMinDigits, pListData,nListIndex);
+ else
+ FillAnalyse(nCol1,static_cast<SCROW>(nRow),
+ nCol2,static_cast<SCROW>(nRow), eFillCmd,eDateCmd,
+ nInc,nMinDigits, pListData,nListIndex);
+
+ if (bVertical)
+ aCol[nCol].Resize( aCol[nCol].GetCellCount() + nFillCount );
+
+ if (pListData)
+ {
+ USHORT nListCount = pListData->GetSubCount();
+ if ( !bPositive )
+ {
+ // nListIndex auf FillAnalyse zeigt auf den letzten Eintrag -> anpassen
+ ULONG nSub = nISrcStart - nISrcEnd;
+ for (ULONG i=0; i<nSub; i++)
+ {
+ if (nListIndex == 0) nListIndex = nListCount;
+ --nListIndex;
+ }
+ }
+
+ rInner = nIStart;
+ while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
+ {
+ if (bPositive)
+ {
+ ++nListIndex;
+ if (nListIndex >= nListCount) nListIndex = 0;
+ }
+ else
+ {
+ if (nListIndex == 0) nListIndex = nListCount;
+ --nListIndex;
+ }
+ aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScStringCell(pListData->GetSubStr(nListIndex)));
+
+ if (rInner == nIEnd) break;
+ if (bPositive) ++rInner; else --rInner;
+ }
+ nProgress += nIMax - nIMin + 1;
+ rProgress.SetStateOnPercent( nProgress );
+ }
+ else if (eFillCmd == FILL_SIMPLE) // Auffuellen mit Muster
+ {
+ ULONG nSource = nISrcStart;
+ double nDelta;
+ if ( nScFillModeMouseModifier & KEY_MOD1 )
+ nDelta = 0.0;
+ else if ( bPositive )
+ nDelta = 1.0;
+ else
+ nDelta = -1.0;
+ double nVal = 0.0;
+ ULONG nFormulaCounter = nActFormCnt;
+ BOOL bFirst = TRUE;
+ BOOL bGetCell = TRUE;
+ USHORT nCellDigits = 0;
+ short nHeadNoneTail = 0;
+ sal_Int32 nStringValue = 0;
+ String aValue;
+ ScBaseCell* pSrcCell = NULL;
+ CellType eCellType = CELLTYPE_NONE;
+ BOOL bIsOrdinalSuffix = FALSE;
+
+ rInner = nIStart;
+ while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
+ {
+ if ( bGetCell )
+ {
+ if (bVertical) // rInner&:=nRow, rOuter&:=nCol
+ pSrcCell = aCol[nCol].GetCell( static_cast<SCROW>(nSource) );
+ else // rInner&:=nCol, rOuter&:=nRow
+ pSrcCell = aCol[nSource].GetCell( static_cast<SCROW>(nRow) );
+ bGetCell = FALSE;
+ if ( pSrcCell )
+ {
+ eCellType = pSrcCell->GetCellType();
+ switch ( eCellType )
+ {
+ case CELLTYPE_VALUE:
+ nVal = ((ScValueCell*)pSrcCell)->GetValue();
+ break;
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ if ( eCellType == CELLTYPE_STRING )
+ ((ScStringCell*)pSrcCell)->GetString( aValue );
+ else
+ ((ScEditCell*)pSrcCell)->GetString( aValue );
+ if ( !(nScFillModeMouseModifier & KEY_MOD1) )
+ {
+ nCellDigits = 0; // look at each source cell individually
+ nHeadNoneTail = lcl_DecompValueString(
+ aValue, nStringValue, &nCellDigits );
+
+ bIsOrdinalSuffix = aValue.Equals(
+ ScGlobal::GetOrdinalSuffix( nStringValue));
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else
+ eCellType = CELLTYPE_NONE;
+ }
+ switch (eCellType)
+ {
+ case CELLTYPE_VALUE:
+ aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScValueCell(nVal + nDelta));
+ break;
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ if ( nHeadNoneTail )
+ {
+ // #i48009# with the "nStringValue+(long)nDelta" expression within the
+ // lcl_ValueString calls, gcc 3.4.1 makes wrong optimizations (ok in 3.4.3),
+ // so nNextValue is now calculated ahead.
+ sal_Int32 nNextValue = nStringValue+(sal_Int32)nDelta;
+
+ String aStr;
+ if ( nHeadNoneTail < 0 )
+ {
+ aCol[nCol].Insert( static_cast<SCROW>(nRow),
+ lcl_getSuffixCell( pDocument,
+ nNextValue, nCellDigits, aValue,
+ eCellType, bIsOrdinalSuffix));
+ }
+ else
+ {
+ aStr = aValue;
+ aStr += lcl_ValueString( nNextValue, nCellDigits );
+ aCol[nCol].Insert( static_cast<SCROW>(nRow),
+ new ScStringCell( aStr));
+ }
+ }
+ else
+ {
+ ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab );
+ switch ( eCellType )
+ {
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ aCol[nCol].Insert( aDestPos.Row(), pSrcCell->CloneWithoutNote( *pDocument ) );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ break;
+ case CELLTYPE_FORMULA :
+ FillFormula( nFormulaCounter, bFirst,
+ (ScFormulaCell*) pSrcCell,
+ static_cast<SCCOL>(nCol),
+ static_cast<SCROW>(nRow), (rInner == nIEnd) );
+ if (nFormulaCounter - nActFormCnt > nMaxFormCnt)
+ nMaxFormCnt = nFormulaCounter - nActFormCnt;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (nSource==nISrcEnd)
+ {
+ if ( nSource != nISrcStart )
+ { // mehr als eine Source-Zelle
+ nSource = nISrcStart;
+ bGetCell = TRUE;
+ }
+ if ( !(nScFillModeMouseModifier & KEY_MOD1) )
+ {
+ if ( bPositive )
+ nDelta += 1.0;
+ else
+ nDelta -= 1.0;
+ }
+ nFormulaCounter = nActFormCnt;
+ bFirst = FALSE;
+ }
+ else if (bPositive)
+ {
+ ++nSource;
+ bGetCell = TRUE;
+ }
+ else
+ {
+ --nSource;
+ bGetCell = TRUE;
+ }
+
+ // Progress in der inneren Schleife nur bei teuren Zellen,
+ // und auch dann nicht fuer jede einzelne
+
+ ++nProgress;
+ if ( eCellType == CELLTYPE_FORMULA || eCellType == CELLTYPE_EDIT )
+ rProgress.SetStateOnPercent( nProgress );
+
+ if (rInner == nIEnd) break;
+ if (bPositive) ++rInner; else --rInner;
+ }
+ rProgress.SetStateOnPercent( nProgress );
+ }
+ else
+ {
+ if (!bPositive)
+ nInc = -nInc;
+ double nEndVal = (nInc>=0.0) ? MAXDOUBLE : -MAXDOUBLE;
+ if (bVertical)
+ FillSeries( static_cast<SCCOL>(nCol), nRow1,
+ static_cast<SCCOL>(nCol), nRow2, nFillCount, eFillDir,
+ eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, FALSE,
+ rProgress );
+ else
+ FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2,
+ static_cast<SCROW>(nRow), nFillCount, eFillDir,
+ eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, FALSE,
+ rProgress );
+ nProgress = rProgress.GetState();
+ }
+
+ nActFormCnt += nMaxFormCnt;
+ }
+}
+
+String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
+{
+ String aValue;
+
+ SCCOL nCol1 = rSource.aStart.Col();
+ SCROW nRow1 = rSource.aStart.Row();
+ SCCOL nCol2 = rSource.aEnd.Col();
+ SCROW nRow2 = rSource.aEnd.Row();
+ BOOL bOk = TRUE;
+ long nIndex = 0;
+ ULONG nSrcCount = 0;
+ FillDir eFillDir = FILL_TO_BOTTOM;
+ if ( nEndX == nCol2 && nEndY == nRow2 ) // leer
+ bOk = FALSE;
+ else if ( nEndX == nCol2 ) // nach oben/unten
+ {
+ nEndX = nCol2 = nCol1; // nur erste Spalte ansehen
+ nSrcCount = nRow2 - nRow1 + 1;
+ nIndex = ((long)nEndY) - nRow1; // kann negativ werden
+ if ( nEndY >= nRow1 )
+ eFillDir = FILL_TO_BOTTOM;
+ else
+ eFillDir = FILL_TO_TOP;
+ }
+ else if ( nEndY == nRow2 ) // nach links/rechts
+ {
+ nEndY = nRow2 = nRow1; // nur erste Zeile ansehen
+ nSrcCount = nCol2 - nCol1 + 1;
+ nIndex = ((long)nEndX) - nCol1; // kann negativ werden
+ if ( nEndX >= nCol1 )
+ eFillDir = FILL_TO_RIGHT;
+ else
+ eFillDir = FILL_TO_LEFT;
+ }
+ else // Richtung nicht eindeutig
+ bOk = FALSE;
+
+ if ( bOk )
+ {
+ FillCmd eFillCmd;
+ FillDateCmd eDateCmd;
+ double nInc;
+ USHORT nMinDigits;
+ ScUserListData* pListData = NULL;
+ USHORT nListIndex;
+
+ FillAnalyse(nCol1,nRow1, nCol2,nRow2, eFillCmd,eDateCmd, nInc,nMinDigits, pListData,nListIndex);
+
+ if ( pListData ) // benutzerdefinierte Liste
+ {
+ USHORT nListCount = pListData->GetSubCount();
+ if ( nListCount )
+ {
+ ULONG nSub = nSrcCount - 1; // nListIndex ist vom letzten Source-Eintrag
+ while ( nIndex < sal::static_int_cast<long>(nSub) )
+ nIndex += nListCount;
+ ULONG nPos = ( nListIndex + nIndex - nSub ) % nListCount;
+ aValue = pListData->GetSubStr(sal::static_int_cast<USHORT>(nPos));
+ }
+ }
+ else if ( eFillCmd == FILL_SIMPLE ) // Auffuellen mit Muster
+ {
+ long nPosIndex = nIndex;
+ while ( nPosIndex < 0 )
+ nPosIndex += nSrcCount;
+ ULONG nPos = nPosIndex % nSrcCount;
+ SCCOL nSrcX = nCol1;
+ SCROW nSrcY = nRow1;
+ if ( eFillDir == FILL_TO_TOP || eFillDir == FILL_TO_BOTTOM )
+ nSrcY = sal::static_int_cast<SCROW>( nSrcY + static_cast<SCROW>(nPos) );
+ else
+ nSrcX = sal::static_int_cast<SCCOL>( nSrcX + static_cast<SCCOL>(nPos) );
+
+ ScBaseCell* pCell = GetCell( nSrcX, nSrcY );
+ if ( pCell )
+ {
+ sal_Int32 nDelta;
+ if (nIndex >= 0)
+ nDelta = nIndex / nSrcCount;
+ else
+ nDelta = ( nIndex - nSrcCount + 1 ) / nSrcCount; // -1 -> -1
+
+ CellType eType = pCell->GetCellType();
+ switch ( eType )
+ {
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ {
+ if ( eType == CELLTYPE_STRING )
+ ((ScStringCell*)pCell)->GetString( aValue );
+ else
+ ((ScEditCell*)pCell)->GetString( aValue );
+ if ( !(nScFillModeMouseModifier & KEY_MOD1) )
+ {
+ sal_Int32 nVal;
+ USHORT nCellDigits = 0; // look at each source cell individually
+ short nFlag = lcl_DecompValueString( aValue, nVal, &nCellDigits );
+ if ( nFlag < 0 )
+ {
+ if (aValue.Equals( ScGlobal::GetOrdinalSuffix( nVal)))
+ aValue = ScGlobal::GetOrdinalSuffix( nVal + nDelta);
+
+ aValue.Insert( lcl_ValueString( nVal + nDelta, nCellDigits ), 0 );
+ }
+ else if ( nFlag > 0 )
+ aValue += lcl_ValueString( nVal + nDelta, nCellDigits );
+ }
+ }
+ break;
+ case CELLTYPE_VALUE:
+ {
+ // dabei kann's keinen Ueberlauf geben...
+ double nVal = ((ScValueCell*)pCell)->GetValue();
+ if ( !(nScFillModeMouseModifier & KEY_MOD1) )
+ nVal += (double) nDelta;
+
+ Color* pColor;
+ ULONG nNumFmt = GetNumberFormat( nSrcX, nSrcY );
+ pDocument->GetFormatTable()->
+ GetOutputString( nVal, nNumFmt, aValue, &pColor );
+ }
+ break;
+ // Formeln nicht
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ else if ( eFillCmd == FILL_LINEAR || eFillCmd == FILL_DATE ) // Werte
+ {
+ BOOL bValueOk;
+ double nStart;
+ sal_Int32 nVal = 0;
+ short nHeadNoneTail = 0;
+ ScBaseCell* pCell = GetCell( nCol1, nRow1 );
+ if ( pCell )
+ {
+ CellType eType = pCell->GetCellType();
+ switch ( eType )
+ {
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ {
+ if ( eType == CELLTYPE_STRING )
+ ((ScStringCell*)pCell)->GetString( aValue );
+ else
+ ((ScEditCell*)pCell)->GetString( aValue );
+ nHeadNoneTail = lcl_DecompValueString( aValue, nVal );
+ if ( nHeadNoneTail )
+ nStart = (double)nVal;
+ else
+ nStart = 0.0;
+ }
+ break;
+ case CELLTYPE_VALUE:
+ nStart = ((ScValueCell*)pCell)->GetValue();
+ break;
+ case CELLTYPE_FORMULA:
+ nStart = ((ScFormulaCell*)pCell)->GetValue();
+ break;
+ default:
+ nStart = 0.0;
+ }
+ }
+ else
+ nStart = 0.0;
+ if ( eFillCmd == FILL_LINEAR )
+ {
+ double nAdd = nInc;
+ bValueOk = ( SubTotal::SafeMult( nAdd, (double) nIndex ) &&
+ SubTotal::SafePlus( nStart, nAdd ) );
+ }
+ else // Datum
+ {
+ bValueOk = TRUE;
+ USHORT nDayOfMonth = 0;
+ if ( nIndex < 0 )
+ {
+ nIndex = -nIndex;
+ nInc = -nInc;
+ }
+ for (long i=0; i<nIndex; i++)
+ IncDate( nStart, nDayOfMonth, nInc, eDateCmd );
+ }
+
+ if (bValueOk)
+ {
+ if ( nHeadNoneTail )
+ {
+ if ( nHeadNoneTail < 0 )
+ {
+ if (aValue.Equals( ScGlobal::GetOrdinalSuffix( nVal)))
+ aValue = ScGlobal::GetOrdinalSuffix( (sal_Int32)nStart );
+
+ aValue.Insert( lcl_ValueString( (sal_Int32)nStart, nMinDigits ), 0 );
+ }
+ else
+ aValue += lcl_ValueString( (sal_Int32)nStart, nMinDigits );
+ }
+ else
+ {
+ //! Zahlformat je nach Index holen?
+ Color* pColor;
+ ULONG nNumFmt = GetNumberFormat( nCol1, nRow1 );
+ pDocument->GetFormatTable()->
+ GetOutputString( nStart, nNumFmt, aValue, &pColor );
+ }
+ }
+ }
+ else
+ {
+ DBG_ERROR("GetAutoFillPreview: falscher Modus");
+ }
+ }
+
+ return aValue;
+}
+
+void ScTable::IncDate(double& rVal, USHORT& nDayOfMonth, double nStep, FillDateCmd eCmd)
+{
+ if (eCmd == FILL_DAY)
+ {
+ rVal += nStep;
+ return;
+ }
+
+ // class Date Grenzen
+ const USHORT nMinYear = 1583;
+ const USHORT nMaxYear = 9956;
+
+ long nInc = (long) nStep; // nach oben/unten begrenzen ?
+ Date aNullDate = *pDocument->GetFormatTable()->GetNullDate();
+ Date aDate = aNullDate;
+ aDate += (long)rVal;
+ switch (eCmd)
+ {
+ case FILL_WEEKDAY:
+ {
+ aDate += nInc;
+ DayOfWeek eWeekDay = aDate.GetDayOfWeek();
+ if (nInc >= 0)
+ {
+ if (eWeekDay == SATURDAY)
+ aDate += 2;
+ else if (eWeekDay == SUNDAY)
+ aDate += 1;
+ }
+ else
+ {
+ if (eWeekDay == SATURDAY)
+ aDate -= 1;
+ else if (eWeekDay == SUNDAY)
+ aDate -= 2;
+ }
+ }
+ break;
+ case FILL_MONTH:
+ {
+ if ( nDayOfMonth == 0 )
+ nDayOfMonth = aDate.GetDay(); // init
+ long nMonth = aDate.GetMonth();
+ long nYear = aDate.GetYear();
+
+ nMonth += nInc;
+
+ if (nInc >= 0)
+ {
+ if (nMonth > 12)
+ {
+ long nYAdd = (nMonth-1) / 12;
+ nMonth -= nYAdd * 12;
+ nYear += nYAdd;
+ }
+ }
+ else
+ {
+ if (nMonth < 1)
+ {
+ long nYAdd = 1 - nMonth / 12; // positiv
+ nMonth += nYAdd * 12;
+ nYear -= nYAdd;
+ }
+ }
+
+ if ( nYear < nMinYear )
+ aDate = Date( 1,1, nMinYear );
+ else if ( nYear > nMaxYear )
+ aDate = Date( 31,12, nMaxYear );
+ else
+ {
+ aDate.SetMonth((USHORT) nMonth);
+ aDate.SetYear((USHORT) nYear);
+ if ( nDayOfMonth > 28 )
+ aDate.SetDay( Min( aDate.GetDaysInMonth(), nDayOfMonth ) );
+ }
+ }
+ break;
+ case FILL_YEAR:
+ {
+ long nYear = aDate.GetYear();
+ nYear += nInc;
+ if ( nYear < nMinYear )
+ aDate = Date( 1,1, nMinYear );
+ else if ( nYear > nMaxYear )
+ aDate = Date( 31,12, nMaxYear );
+ else
+ aDate.SetYear((USHORT) nYear);
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ rVal = aDate - aNullDate;
+}
+
+void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ ULONG nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
+ double nStepValue, double nMaxValue, USHORT nArgMinDigits,
+ BOOL bAttribs, ScProgress& rProgress )
+{
+ //
+ // Richtung auswerten
+ //
+
+ BOOL bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
+ BOOL bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
+
+ ULONG nCol = 0;
+ ULONG nRow = 0;
+ ULONG& rInner = bVertical ? nRow : nCol; // Schleifenvariablen
+ ULONG& rOuter = bVertical ? nCol : nRow;
+ ULONG nOStart;
+ ULONG nOEnd;
+ ULONG nIStart;
+ ULONG nIEnd;
+ ULONG nISource;
+
+ if (bVertical)
+ {
+ nFillCount += (nRow2 - nRow1);
+ if (nFillCount == 0)
+ return;
+ nOStart = nCol1;
+ nOEnd = nCol2;
+ if (bPositive)
+ {
+ nISource = nRow1;
+ nIStart = nRow1 + 1;
+ nIEnd = nRow1 + nFillCount;
+ }
+ else
+ {
+ nISource = nRow2;
+ nIStart = nRow2 - 1;
+ nIEnd = nRow2 - nFillCount;
+ }
+ }
+ else
+ {
+ nFillCount += (nCol2 - nCol1);
+ if (nFillCount == 0)
+ return;
+ nOStart = nRow1;
+ nOEnd = nRow2;
+ if (bPositive)
+ {
+ nISource = nCol1;
+ nIStart = nCol1 + 1;
+ nIEnd = nCol1 + nFillCount;
+ }
+ else
+ {
+ nISource = nCol2;
+ nIStart = nCol2 - 1;
+ nIEnd = nCol2 - nFillCount;
+ }
+ }
+
+ ULONG nIMin = nIStart;
+ ULONG nIMax = nIEnd;
+ PutInOrder(nIMin,nIMax);
+ USHORT nDel = bAttribs ? IDF_AUTOFILL : (IDF_AUTOFILL & IDF_CONTENTS);
+ if (bVertical)
+ DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), nDel);
+ else
+ DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, nDel);
+
+ ULONG nProgress = rProgress.GetState();
+
+ //
+ // ausfuehren
+ //
+
+ ULONG nActFormCnt = 0;
+ for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
+ {
+ BOOL bFirst = TRUE;
+ rInner = nISource;
+ ScBaseCell* pSrcCell = aCol[nCol].GetCell(static_cast<SCROW>(nRow));
+
+ if (bVertical && bAttribs)
+ aCol[nCol].Resize( aCol[nCol].GetCellCount() + nFillCount );
+
+ if (bAttribs)
+ {
+ const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
+ if (bVertical)
+ aCol[nCol].SetPatternArea( static_cast<SCROW>(nIMin),
+ static_cast<SCROW>(nIMax), *pSrcPattern, TRUE );
+ else
+ for (SCCOL nAtCol = static_cast<SCCOL>(nIMin); nAtCol <= sal::static_int_cast<SCCOL>(nIMax); nAtCol++)
+ aCol[nAtCol].SetPattern(static_cast<SCROW>(nRow), *pSrcPattern, TRUE);
+ }
+
+ if (pSrcCell)
+ {
+ CellType eCellType = pSrcCell->GetCellType();
+
+ if (eFillCmd == FILL_SIMPLE) // kopieren
+ {
+ if (eCellType == CELLTYPE_FORMULA)
+ {
+ for (rInner = nIMin; rInner <= nIMax; rInner++)
+ {
+ ULONG nInd = nActFormCnt;
+ FillFormula(nInd, bFirst, (ScFormulaCell*)pSrcCell,
+ static_cast<SCCOL>(nCol), nRow, (rInner == nIEnd) );
+ bFirst = FALSE;
+ rProgress.SetStateOnPercent( ++nProgress );
+ }
+ }
+ else if (eCellType != CELLTYPE_NOTE)
+ {
+ for (rInner = nIMin; rInner <= nIMax; rInner++)
+ {
+ ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab );
+ aCol[nCol].Insert( aDestPos.Row(), pSrcCell->CloneWithoutNote( *pDocument ) );
+ }
+ nProgress += nIMax - nIMin + 1;
+ rProgress.SetStateOnPercent( nProgress );
+ }
+ }
+ else if (eCellType == CELLTYPE_VALUE || eCellType == CELLTYPE_FORMULA)
+ {
+ double nStartVal;
+ if (eCellType == CELLTYPE_VALUE)
+ nStartVal = ((ScValueCell*)pSrcCell)->GetValue();
+ else
+ nStartVal = ((ScFormulaCell*)pSrcCell)->GetValue();
+ double nVal = nStartVal;
+ long nIndex = 0;
+
+ BOOL bError = FALSE;
+ BOOL bOverflow = FALSE;
+
+ USHORT nDayOfMonth = 0;
+ rInner = nIStart;
+ while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
+ {
+ if (!bError && !bOverflow)
+ {
+ switch (eFillCmd)
+ {
+ case FILL_LINEAR:
+ {
+ // #86365# use multiplication instead of repeated addition
+ // to avoid accumulating rounding errors
+ nVal = nStartVal;
+ double nAdd = nStepValue;
+ if ( !SubTotal::SafeMult( nAdd, (double) ++nIndex ) ||
+ !SubTotal::SafePlus( nVal, nAdd ) )
+ bError = TRUE;
+ }
+ break;
+ case FILL_GROWTH:
+ if (!SubTotal::SafeMult(nVal, nStepValue))
+ bError = TRUE;
+ break;
+ case FILL_DATE:
+ if (fabs(nVal) > _D_MAX_LONG_)
+ bError = TRUE;
+ else
+ IncDate(nVal, nDayOfMonth, nStepValue, eFillDateCmd);
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (nStepValue >= 0)
+ {
+ if (nVal > nMaxValue) // Zielwert erreicht?
+ {
+ nVal = nMaxValue;
+ bOverflow = TRUE;
+ }
+ }
+ else
+ {
+ if (nVal < nMaxValue)
+ {
+ nVal = nMaxValue;
+ bOverflow = TRUE;
+ }
+ }
+ }
+
+ if (bError)
+ aCol[nCol].SetError(static_cast<SCROW>(nRow), errNoValue);
+ else if (!bOverflow)
+ aCol[nCol].SetValue(static_cast<SCROW>(nRow), nVal);
+
+ if (rInner == nIEnd) break;
+ if (bPositive) ++rInner; else --rInner;
+ }
+ nProgress += nIMax - nIMin + 1;
+ rProgress.SetStateOnPercent( nProgress );
+ }
+ else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
+ {
+ if ( nStepValue >= 0 )
+ {
+ if ( nMaxValue >= (double)LONG_MAX )
+ nMaxValue = (double)LONG_MAX - 1;
+ }
+ else
+ {
+ if ( nMaxValue <= (double)LONG_MIN )
+ nMaxValue = (double)LONG_MIN + 1;
+ }
+ String aValue;
+ if (eCellType == CELLTYPE_STRING)
+ ((ScStringCell*)pSrcCell)->GetString( aValue );
+ else
+ ((ScEditCell*)pSrcCell)->GetString( aValue );
+ sal_Int32 nStringValue;
+ USHORT nMinDigits = nArgMinDigits;
+ short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits );
+ if ( nHeadNoneTail )
+ {
+ double nStartVal = (double)nStringValue;
+ double nVal = nStartVal;
+ long nIndex = 0;
+ BOOL bError = FALSE;
+ BOOL bOverflow = FALSE;
+
+ BOOL bIsOrdinalSuffix = aValue.Equals( ScGlobal::GetOrdinalSuffix(
+ (sal_Int32)nStartVal));
+
+ rInner = nIStart;
+ while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
+ {
+ if (!bError && !bOverflow)
+ {
+ switch (eFillCmd)
+ {
+ case FILL_LINEAR:
+ {
+ // #86365# use multiplication instead of repeated addition
+ // to avoid accumulating rounding errors
+ nVal = nStartVal;
+ double nAdd = nStepValue;
+ if ( !SubTotal::SafeMult( nAdd, (double) ++nIndex ) ||
+ !SubTotal::SafePlus( nVal, nAdd ) )
+ bError = TRUE;
+ }
+ break;
+ case FILL_GROWTH:
+ if (!SubTotal::SafeMult(nVal, nStepValue))
+ bError = TRUE;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (nStepValue >= 0)
+ {
+ if (nVal > nMaxValue) // Zielwert erreicht?
+ {
+ nVal = nMaxValue;
+ bOverflow = TRUE;
+ }
+ }
+ else
+ {
+ if (nVal < nMaxValue)
+ {
+ nVal = nMaxValue;
+ bOverflow = TRUE;
+ }
+ }
+ }
+
+ if (bError)
+ aCol[nCol].SetError(static_cast<SCROW>(nRow), errNoValue);
+ else if (!bOverflow)
+ {
+ nStringValue = (sal_Int32)nVal;
+ String aStr;
+ if ( nHeadNoneTail < 0 )
+ {
+ aCol[nCol].Insert( static_cast<SCROW>(nRow),
+ lcl_getSuffixCell( pDocument,
+ nStringValue, nMinDigits, aValue,
+ eCellType, bIsOrdinalSuffix ));
+ }
+ else
+ {
+ aStr = aValue;
+ aStr += lcl_ValueString( nStringValue, nMinDigits );
+ ScStringCell* pCell = new ScStringCell( aStr );
+ aCol[nCol].Insert( static_cast<SCROW>(nRow), pCell );
+ }
+ }
+
+ if (rInner == nIEnd) break;
+ if (bPositive) ++rInner; else --rInner;
+ }
+ }
+ nProgress += nIMax - nIMin + 1;
+ rProgress.SetStateOnPercent( nProgress );
+ }
+ }
+ else
+ {
+ nProgress += nIMax - nIMin + 1;
+ rProgress.SetStateOnPercent( nProgress );
+ }
+ ++nActFormCnt;
+ }
+}
+
+void ScTable::Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ ULONG nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
+ double nStepValue, double nMaxValue)
+{
+ ULONG nProgCount;
+ if (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP)
+ nProgCount = nCol2 - nCol1 + 1;
+ else
+ nProgCount = nRow2 - nRow1 + 1;
+ nProgCount *= nFillCount;
+ ScProgress aProgress( pDocument->GetDocumentShell(),
+ ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount );
+
+ bSharedNameInserted = FALSE;
+
+ if (eFillCmd == FILL_AUTO)
+ FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, aProgress);
+ else
+ FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir,
+ eFillCmd, eFillDateCmd, nStepValue, nMaxValue, 0, TRUE, aProgress);
+
+ if (bSharedNameInserted) // Wurde Shared-Name eingefuegt?
+ pDocument->GetRangeName()->SetSharedMaxIndex(
+ pDocument->GetRangeName()->GetSharedMaxIndex()+1); // dann hochzaehlen
+}
+
+
+void ScTable::AutoFormatArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ const ScPatternAttr& rAttr, USHORT nFormatNo)
+{
+ ScAutoFormat* pAutoFormat = ScGlobal::GetAutoFormat();
+ if (pAutoFormat)
+ {
+ ScAutoFormatData* pData = (*pAutoFormat)[nFormatNo];
+ if (pData)
+ {
+// ScPatternAttr aPattern(pDocument->GetPool());
+// pData->FillToItemSet(nIndex, aPattern.GetItemSet(), *pDocument);
+ ApplyPatternArea(nStartCol, nStartRow, nEndCol, nEndRow, rAttr);
+ }
+ }
+}
+
+void ScTable::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ USHORT nFormatNo )
+{
+ if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
+ {
+ ScAutoFormat* pAutoFormat = ScGlobal::GetAutoFormat();
+ if (pAutoFormat)
+ {
+ ScAutoFormatData* pData = (*pAutoFormat)[nFormatNo];
+ if (pData)
+ {
+ ScPatternAttr* pPatternAttrs[16];
+ for (sal_uInt8 i = 0; i < 16; ++i)
+ {
+ pPatternAttrs[i] = new ScPatternAttr(pDocument->GetPool());
+ pData->FillToItemSet(i, pPatternAttrs[i]->GetItemSet(), *pDocument);
+ }
+
+ SCCOL nCol = nStartCol;
+ SCROW nRow = nStartRow;
+ USHORT nIndex = 0;
+ // Linke obere Ecke
+ AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
+ // Linke Spalte
+ if (pData->IsEqualData(4, 8))
+ AutoFormatArea(nStartCol, nStartRow + 1, nStartCol, nEndRow - 1, *pPatternAttrs[4], nFormatNo);
+ else
+ {
+ nIndex = 4;
+ for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
+ {
+ AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
+ if (nIndex == 4)
+ nIndex = 8;
+ else
+ nIndex = 4;
+ }
+ }
+ // Linke untere Ecke
+ nRow = nEndRow;
+ nIndex = 12;
+ AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
+ // Rechte obere Ecke
+ nCol = nEndCol;
+ nRow = nStartRow;
+ nIndex = 3;
+ AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
+ // Rechte Spalte
+ if (pData->IsEqualData(7, 11))
+ AutoFormatArea(nEndCol, nStartRow + 1, nEndCol, nEndRow - 1, *pPatternAttrs[7], nFormatNo);
+ else
+ {
+ nIndex = 7;
+ for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
+ {
+ AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
+ if (nIndex == 7)
+ nIndex = 11;
+ else
+ nIndex = 7;
+ }
+ }
+ // Rechte untere Ecke
+ nRow = nEndRow;
+ nIndex = 15;
+ AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
+ nRow = nStartRow;
+ nIndex = 1;
+ for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
+ {
+ AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
+ if (nIndex == 1)
+ nIndex = 2;
+ else
+ nIndex = 1;
+ }
+ // Untere Zeile
+ nRow = nEndRow;
+ nIndex = 13;
+ for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
+ {
+ AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
+ if (nIndex == 13)
+ nIndex = 14;
+ else
+ nIndex = 13;
+ }
+ // Boddy
+ if ((pData->IsEqualData(5, 6)) && (pData->IsEqualData(9, 10)) && (pData->IsEqualData(5, 9)))
+ AutoFormatArea(nStartCol + 1, nStartRow + 1, nEndCol-1, nEndRow - 1, *pPatternAttrs[5], nFormatNo);
+ else
+ {
+ if ((pData->IsEqualData(5, 9)) && (pData->IsEqualData(6, 10)))
+ {
+ nIndex = 5;
+ for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
+ {
+ AutoFormatArea(nCol, nStartRow + 1, nCol, nEndRow - 1, *pPatternAttrs[nIndex], nFormatNo);
+ if (nIndex == 5)
+ nIndex = 6;
+ else
+ nIndex = 5;
+ }
+ }
+ else
+ {
+ nIndex = 5;
+ for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
+ {
+ for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
+ {
+ AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
+ if ((nIndex == 5) || (nIndex == 9))
+ {
+ if (nIndex == 5)
+ nIndex = 9;
+ else
+ nIndex = 5;
+ }
+ else
+ {
+ if (nIndex == 6)
+ nIndex = 10;
+ else
+ nIndex = 6;
+ }
+ } // for nRow
+ if ((nIndex == 5) || (nIndex == 9))
+ nIndex = 6;
+ else
+ nIndex = 5;
+ } // for nCol
+ } // if not equal Column
+ } // if not all equal
+
+ for (sal_uInt8 j = 0; j < 16; ++j)
+ delete pPatternAttrs[j];
+ } // if AutoFormatData != NULL
+ } // if AutoFormat != NULL
+ } // if ValidColRow
+}
+
+void ScTable::GetAutoFormatAttr(SCCOL nCol, SCROW nRow, USHORT nIndex, ScAutoFormatData& rData)
+{
+ UINT32 nFormatIndex = GetNumberFormat( nCol, nRow );
+ ScNumFormatAbbrev aNumFormat( nFormatIndex, *pDocument->GetFormatTable() );
+ rData.GetFromItemSet( nIndex, GetPattern( nCol, nRow )->GetItemSet(), aNumFormat );
+}
+
+#define LF_LEFT 1
+#define LF_TOP 2
+#define LF_RIGHT 4
+#define LF_BOTTOM 8
+#define LF_ALL (LF_LEFT | LF_TOP | LF_RIGHT | LF_BOTTOM)
+
+void ScTable::GetAutoFormatFrame(SCCOL nCol, SCROW nRow, USHORT nFlags, USHORT nIndex, ScAutoFormatData& rData)
+{
+ const SvxBoxItem* pTheBox = (SvxBoxItem*)GetAttr(nCol, nRow, ATTR_BORDER);
+ const SvxBoxItem* pLeftBox = (SvxBoxItem*)GetAttr(nCol - 1, nRow, ATTR_BORDER);
+ const SvxBoxItem* pTopBox = (SvxBoxItem*)GetAttr(nCol, nRow - 1, ATTR_BORDER);
+ const SvxBoxItem* pRightBox = (SvxBoxItem*)GetAttr(nCol + 1, nRow, ATTR_BORDER);
+ const SvxBoxItem* pBottomBox = (SvxBoxItem*)GetAttr(nCol, nRow + 1, ATTR_BORDER);
+
+ SvxBoxItem aBox( ATTR_BORDER );
+ if (nFlags & LF_LEFT)
+ {
+ if (pLeftBox)
+ {
+ if (ScHasPriority(pTheBox->GetLeft(), pLeftBox->GetRight()))
+ aBox.SetLine(pTheBox->GetLeft(), BOX_LINE_LEFT);
+ else
+ aBox.SetLine(pLeftBox->GetRight(), BOX_LINE_LEFT);
+ }
+ else
+ aBox.SetLine(pTheBox->GetLeft(), BOX_LINE_LEFT);
+ }
+ if (nFlags & LF_TOP)
+ {
+ if (pTopBox)
+ {
+ if (ScHasPriority(pTheBox->GetTop(), pTopBox->GetBottom()))
+ aBox.SetLine(pTheBox->GetTop(), BOX_LINE_TOP);
+ else
+ aBox.SetLine(pTopBox->GetBottom(), BOX_LINE_TOP);
+ }
+ else
+ aBox.SetLine(pTheBox->GetTop(), BOX_LINE_TOP);
+ }
+ if (nFlags & LF_RIGHT)
+ {
+ if (pRightBox)
+ {
+ if (ScHasPriority(pTheBox->GetRight(), pRightBox->GetLeft()))
+ aBox.SetLine(pTheBox->GetRight(), BOX_LINE_RIGHT);
+ else
+ aBox.SetLine(pRightBox->GetLeft(), BOX_LINE_RIGHT);
+ }
+ else
+ aBox.SetLine(pTheBox->GetRight(), BOX_LINE_RIGHT);
+ }
+ if (nFlags & LF_BOTTOM)
+ {
+ if (pBottomBox)
+ {
+ if (ScHasPriority(pTheBox->GetBottom(), pBottomBox->GetTop()))
+ aBox.SetLine(pTheBox->GetBottom(), BOX_LINE_BOTTOM);
+ else
+ aBox.SetLine(pBottomBox->GetTop(), BOX_LINE_BOTTOM);
+ }
+ else
+ aBox.SetLine(pTheBox->GetBottom(), BOX_LINE_BOTTOM);
+ }
+ rData.PutItem( nIndex, aBox );
+}
+
+void ScTable::GetAutoFormatData(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScAutoFormatData& rData)
+{
+ if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
+ {
+ if ((nEndCol - nStartCol >= 3) && (nEndRow - nStartRow >= 3))
+ {
+ // Linke obere Ecke
+ GetAutoFormatAttr(nStartCol, nStartRow, 0, rData);
+ GetAutoFormatFrame(nStartCol, nStartRow, LF_ALL, 0, rData);
+ // Linke Spalte
+ GetAutoFormatAttr(nStartCol, nStartRow + 1, 4, rData);
+ GetAutoFormatAttr(nStartCol, nStartRow + 2, 8, rData);
+ GetAutoFormatFrame(nStartCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 4, rData);
+ if (nEndRow - nStartRow >= 4)
+ GetAutoFormatFrame(nStartCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 8, rData);
+ else
+ rData.CopyItem( 8, 4, ATTR_BORDER );
+ // Linke untere Ecke
+ GetAutoFormatAttr(nStartCol, nEndRow, 12, rData);
+ GetAutoFormatFrame(nStartCol, nEndRow, LF_ALL, 12, rData);
+ // Rechte obere Ecke
+ GetAutoFormatAttr(nEndCol, nStartRow, 3, rData);
+ GetAutoFormatFrame(nEndCol, nStartRow, LF_ALL, 3, rData);
+ // Rechte Spalte
+ GetAutoFormatAttr(nEndCol, nStartRow + 1, 7, rData);
+ GetAutoFormatAttr(nEndCol, nStartRow + 2, 11, rData);
+ GetAutoFormatFrame(nEndCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 7, rData);
+ if (nEndRow - nStartRow >= 4)
+ GetAutoFormatFrame(nEndCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 11, rData);
+ else
+ rData.CopyItem( 11, 7, ATTR_BORDER );
+ // Rechte untere Ecke
+ GetAutoFormatAttr(nEndCol, nEndRow, 15, rData);
+ GetAutoFormatFrame(nEndCol, nEndRow, LF_ALL, 15, rData);
+ // Ober Zeile
+ GetAutoFormatAttr(nStartCol + 1, nStartRow, 1, rData);
+ GetAutoFormatAttr(nStartCol + 2, nStartRow, 2, rData);
+ GetAutoFormatFrame(nStartCol + 1, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 1, rData);
+ if (nEndCol - nStartCol >= 4)
+ GetAutoFormatFrame(nStartCol + 2, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 2, rData);
+ else
+ rData.CopyItem( 2, 1, ATTR_BORDER );
+ // Untere Zeile
+ GetAutoFormatAttr(nStartCol + 1, nEndRow, 13, rData);
+ GetAutoFormatAttr(nStartCol + 2, nEndRow, 14, rData);
+ GetAutoFormatFrame(nStartCol + 1, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 13, rData);
+ if (nEndCol - nStartCol >= 4)
+ GetAutoFormatFrame(nStartCol + 2, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 14, rData);
+ else
+ rData.CopyItem( 14, 13, ATTR_BORDER );
+ // Body
+ GetAutoFormatAttr(nStartCol + 1, nStartRow + 1, 5, rData);
+ GetAutoFormatAttr(nStartCol + 2, nStartRow + 1, 6, rData);
+ GetAutoFormatAttr(nStartCol + 1, nStartRow + 2, 9, rData);
+ GetAutoFormatAttr(nStartCol + 2, nStartRow + 2, 10, rData);
+ GetAutoFormatFrame(nStartCol + 1, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 5, rData);
+ if ((nEndCol - nStartCol >= 4) && (nEndRow - nStartRow >= 4))
+ {
+ GetAutoFormatFrame(nStartCol + 2, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 6, rData);
+ GetAutoFormatFrame(nStartCol + 1, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 9, rData);
+ GetAutoFormatFrame(nStartCol + 2, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 10, rData);
+ }
+ else
+ {
+ rData.CopyItem( 6, 5, ATTR_BORDER );
+ rData.CopyItem( 9, 5, ATTR_BORDER );
+ rData.CopyItem( 10, 5, ATTR_BORDER );
+ }
+ }
+ }
+}
+
+void ScTable::SetError( SCCOL nCol, SCROW nRow, USHORT nError)
+{
+ if (ValidColRow(nCol, nRow))
+ aCol[nCol].SetError( nRow, nError );
+}
+
+void ScTable::UpdateInsertTabAbs(SCTAB nTable)
+{
+ for (SCCOL i=0; i <= MAXCOL; i++)
+ aCol[i].UpdateInsertTabAbs(nTable);
+}
+
+//UNUSED2008-05 USHORT ScTable::GetErrorData( SCCOL nCol, SCROW nRow ) const
+//UNUSED2008-05 {
+//UNUSED2008-05 if (ValidColRow(nCol,nRow))
+//UNUSED2008-05 return aCol[nCol].GetErrorData( nRow );
+//UNUSED2008-05 else
+//UNUSED2008-05 return 0;
+//UNUSED2008-05 }
+
+BOOL ScTable::GetNextSpellingCell(SCCOL& rCol, SCROW& rRow, BOOL bInSel,
+ const ScMarkData& rMark) const
+{
+ if (rRow == MAXROW+2) // Tabellenende
+ {
+ rRow = 0;
+ rCol = 0;
+ }
+ else
+ {
+ rRow++;
+ if (rRow == MAXROW+1)
+ {
+ rCol++;
+ rRow = 0;
+ }
+ }
+ if (rCol == MAXCOL+1)
+ return TRUE;
+ else
+ {
+ BOOL bStop = FALSE;
+ while (!bStop)
+ {
+ if (ValidCol(rCol))
+ {
+ bStop = aCol[rCol].GetNextSpellingCell(rRow, bInSel, rMark);
+ if (bStop)
+ return TRUE;
+ else /*if (rRow == MAXROW+1) */
+ {
+ rCol++;
+ rRow = 0;
+ }
+ }
+ else
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void ScTable::RemoveAutoSpellObj()
+{
+ for (SCCOL i=0; i <= MAXCOL; i++)
+ aCol[i].RemoveAutoSpellObj();
+}
+
+BOOL ScTable::TestTabRefAbs(SCTAB nTable)
+{
+ BOOL bRet = FALSE;
+ for (SCCOL i=0; i <= MAXCOL; i++)
+ if (aCol[i].TestTabRefAbs(nTable))
+ bRet = TRUE;
+ return bRet;
+}
+
+void ScTable::CompileDBFormula()
+{
+ for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileDBFormula();
+}
+
+void ScTable::CompileDBFormula( BOOL bCreateFormulaString )
+{
+ for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileDBFormula( bCreateFormulaString );
+}
+
+void ScTable::CompileNameFormula( BOOL bCreateFormulaString )
+{
+ for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileNameFormula( bCreateFormulaString );
+}
+
+void ScTable::CompileColRowNameFormula()
+{
+ for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileColRowNameFormula();
+}
+
+
+
+
+
+
diff --git a/sc/source/core/data/table5.cxx b/sc/source/core/data/table5.cxx
new file mode 100644
index 000000000000..a6ef174e326c
--- /dev/null
+++ b/sc/source/core/data/table5.cxx
@@ -0,0 +1,419 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: table5.cxx,v $
+ * $Revision: 1.14 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include "collect.hxx"
+#include "attrib.hxx"
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "cell.hxx"
+#include "table.hxx"
+#include "column.hxx"
+#include "document.hxx"
+#include "drwlayer.hxx"
+#include "olinetab.hxx"
+#include "userlist.hxx"
+#include "stlsheet.hxx"
+#include "global.hxx"
+#include "rechead.hxx"
+#include "stlpool.hxx"
+#include "stlsheet.hxx"
+#include "brdcst.hxx"
+#include "globstr.hrc"
+
+// STATIC DATA -----------------------------------------------------------
+
+#define GET_SCALEVALUE(set,id) ((const SfxUInt16Item&)(set.Get( id ))).GetValue()
+
+
+void ScTable::UpdatePageBreaks( const ScRange* pUserArea )
+{
+ if ( pDocument->IsImportingXML() )
+ return;
+ if ( !pUserArea && !bPageSizeValid )
+ return;
+
+ SfxStyleSheetBase* pStyle = pDocument->GetStyleSheetPool()->
+ Find( aPageStyle, SFX_STYLE_FAMILY_PAGE );
+ if ( !pStyle )
+ {
+ DBG_ERROR("UpdatePageBreaks: Style nicht gefunden");
+ return;
+ }
+ SfxItemSet* pStyleSet = &pStyle->GetItemSet();
+ const SfxPoolItem* pItem;
+
+ SCCOL nX;
+ SCROW nY;
+ SCCOL nStartCol = 0;
+ SCROW nStartRow = 0;
+ SCCOL nEndCol = MAXCOL;
+ SCROW nEndRow = MAXROW;
+ if (pUserArea)
+ {
+ nStartCol = pUserArea->aStart.Col();
+ nStartRow = pUserArea->aStart.Row();
+ nEndCol = pUserArea->aEnd.Col();
+ nEndRow = pUserArea->aEnd.Row();
+ }
+ else
+ {
+ USHORT nAreaCount = GetPrintRangeCount();
+ if ( nAreaCount > 1 )
+ {
+ // bei mehreren Bereichen nichts anzeigen:
+
+ for (nX=0; nX<MAXCOL; nX++)
+ pColFlags[nX] &= ~CR_PAGEBREAK;
+ pRowFlags->AndValue( 0, MAXROW-1, sal::static_int_cast<BYTE>(~CR_PAGEBREAK) );
+
+ return;
+ }
+ else if ( nAreaCount == 1 )
+ {
+ const ScRange* pArea = GetPrintRange( 0 );
+ if (pArea)
+ {
+ nStartCol = pArea->aStart.Col();
+ nStartRow = pArea->aStart.Row();
+ nEndCol = pArea->aEnd.Col();
+ nEndRow = pArea->aEnd.Row();
+ }
+ } // sonst alles
+ }
+
+ // bSkipBreaks holen:
+
+ BOOL bSkipBreaks = FALSE;
+
+ if ( pStyleSet->GetItemState( ATTR_PAGE_SCALETOPAGES, FALSE, &pItem ) == SFX_ITEM_SET )
+ {
+ DBG_ASSERT( pItem->ISA(SfxUInt16Item), "falsches Item" );
+ bSkipBreaks = ( ((const SfxUInt16Item*)pItem)->GetValue() > 0 );
+ }
+
+ //--------------------------------------------------------------------------
+
+ long nPageSizeX = aPageSizeTwips.Width();
+ long nPageSizeY = aPageSizeTwips.Height();
+
+ // Anfang: Breaks loeschen
+
+ for (nX=0; nX<nStartCol; nX++)
+ pColFlags[nX] &= ~CR_PAGEBREAK;
+ pRowFlags->AndValue( 0, nStartRow-1, sal::static_int_cast<BYTE>(~CR_PAGEBREAK) );
+
+ if (nStartCol > 0)
+ pColFlags[nStartCol] |= CR_PAGEBREAK; //! AREABREAK
+ if (nStartRow > 0)
+ pRowFlags->OrValue( nStartRow, CR_PAGEBREAK); //! AREABREAK
+
+ // Mittelteil: Breaks verteilen
+
+ BOOL bRepeatCol = ( nRepeatStartX != SCCOL_REPEAT_NONE );
+ BOOL bColFound = FALSE;
+ long nSizeX = 0;
+ for (nX=nStartCol; nX<=nEndCol; nX++)
+ {
+ BOOL bStartOfPage = FALSE;
+ long nThisX = ( pColFlags[nX] & CR_HIDDEN ) ? 0 : pColWidth[nX];
+ if ( (nSizeX+nThisX > nPageSizeX) || ((pColFlags[nX] & CR_MANUALBREAK) && !bSkipBreaks) )
+ {
+ pColFlags[nX] |= CR_PAGEBREAK;
+ nSizeX = 0;
+ bStartOfPage = TRUE;
+ }
+ else if (nX != nStartCol)
+ pColFlags[nX] &= ~CR_PAGEBREAK;
+ else
+ bStartOfPage = TRUE;
+
+ if ( bStartOfPage && bRepeatCol && nX>nRepeatStartX && !bColFound )
+ {
+ // subtract size of repeat columns from page size
+ for (SCCOL i=nRepeatStartX; i<=nRepeatEndX; i++)
+ nPageSizeX -= ( pColFlags[i] & CR_HIDDEN ) ? 0 : pColWidth[i];
+ while (nX<=nRepeatEndX)
+ pColFlags[++nX] &= ~CR_PAGEBREAK;
+ bColFound = TRUE;
+ }
+
+ nSizeX += nThisX;
+ }
+
+ // Remove all page breaks in range.
+ pRowFlags->AndValue( nStartRow+1, nEndRow, sal::static_int_cast<BYTE>(~CR_PAGEBREAK) );
+ // And set new page breaks.
+ BOOL bRepeatRow = ( nRepeatStartY != SCROW_REPEAT_NONE );
+ BOOL bRowFound = FALSE;
+ long nSizeY = 0;
+ ScCompressedArrayIterator< SCROW, BYTE> aFlagsIter( *pRowFlags, nStartRow, nEndRow);
+ ScCompressedArrayIterator< SCROW, USHORT> aHeightIter( *pRowHeight, nStartRow, nEndRow);
+ for ( ; aFlagsIter; ++aFlagsIter, ++aHeightIter)
+ {
+ nY = aFlagsIter.GetPos();
+ BOOL bStartOfPage = FALSE;
+ BYTE nFlags = *aFlagsIter;
+ long nThisY = (nFlags & CR_HIDDEN) ? 0 : *aHeightIter;
+ if ( (nSizeY+nThisY > nPageSizeY) || ((nFlags & CR_MANUALBREAK) && !bSkipBreaks) )
+ {
+ pRowFlags->SetValue( nY, nFlags | CR_PAGEBREAK);
+ aFlagsIter.Resync( nY);
+ nSizeY = 0;
+ bStartOfPage = TRUE;
+ }
+ else if (nY != nStartRow)
+ ; // page break already removed
+ else
+ bStartOfPage = TRUE;
+
+ if ( bStartOfPage && bRepeatRow && nY>nRepeatStartY && !bRowFound )
+ {
+ // subtract size of repeat rows from page size
+ unsigned long nHeights = pRowFlags->SumCoupledArrayForCondition(
+ nRepeatStartY, nRepeatEndY, CR_HIDDEN, 0, *pRowHeight);
+#ifdef DBG_UTIL
+ if (nHeights == ::std::numeric_limits<unsigned long>::max())
+ DBG_ERRORFILE("ScTable::UpdatePageBreaks: row heights overflow");
+#endif
+ nPageSizeY -= nHeights;
+ if (nY <= nRepeatEndY)
+ {
+ pRowFlags->AndValue( nY, nRepeatEndY, sal::static_int_cast<BYTE>(~CR_PAGEBREAK) );
+ nY = nRepeatEndY + 1;
+ aFlagsIter.Resync( nY);
+ aHeightIter.Resync( nY);
+ }
+ bRowFound = TRUE;
+ }
+
+ nSizeY += nThisY;
+ }
+
+ // Ende: Breaks loeschen
+
+ if (nEndCol < MAXCOL)
+ {
+ pColFlags[nEndCol+1] |= CR_PAGEBREAK; //! AREABREAK
+ for (nX=nEndCol+2; nX<=MAXCOL; nX++)
+ pColFlags[nX] &= ~CR_PAGEBREAK;
+ }
+ if (nEndRow < MAXROW)
+ {
+ pRowFlags->OrValue( nEndRow+1, CR_PAGEBREAK); //! AREABREAK
+ if (nEndRow+2 <= MAXROW)
+ pRowFlags->AndValue( nEndRow+2, MAXROW, sal::static_int_cast<BYTE>(~CR_PAGEBREAK) );
+ }
+}
+
+void ScTable::RemoveManualBreaks()
+{
+ if (pColFlags)
+ for (SCCOL nCol = 0; nCol <= MAXCOL; nCol++)
+ pColFlags[nCol] &= ~CR_MANUALBREAK;
+
+ if (pRowFlags)
+ pRowFlags->AndValue( 0, MAXROW, sal::static_int_cast<BYTE>(~CR_MANUALBREAK) );
+}
+
+BOOL ScTable::HasManualBreaks() const
+{
+ if (pColFlags)
+ for (SCCOL nCol = 0; nCol <= MAXCOL; nCol++)
+ if ( pColFlags[nCol] & CR_MANUALBREAK )
+ return TRUE;
+
+ if (pRowFlags)
+ if (ValidRow( pRowFlags->GetLastAnyBitAccess( 0, CR_MANUALBREAK)))
+ return TRUE;
+
+ return FALSE;
+}
+
+void ScTable::SetPageSize( const Size& rSize )
+{
+ if ( rSize.Width() != 0 && rSize.Height() != 0 )
+ {
+ bPageSizeValid = TRUE;
+ aPageSizeTwips = rSize;
+ }
+ else
+ bPageSizeValid = FALSE;
+}
+
+Size ScTable::GetPageSize() const
+{
+ if ( bPageSizeValid )
+ return aPageSizeTwips;
+ else
+ return Size(); // leer
+}
+
+void ScTable::SetRepeatArea( SCCOL nStartCol, SCCOL nEndCol, SCROW nStartRow, SCROW nEndRow )
+{
+ nRepeatStartX = nStartCol;
+ nRepeatEndX = nEndCol;
+ nRepeatStartY = nStartRow;
+ nRepeatEndY = nEndRow;
+}
+
+void ScTable::StartListening( const ScAddress& rAddress, SvtListener* pListener )
+{
+ aCol[rAddress.Col()].StartListening( *pListener, rAddress.Row() );
+}
+
+void ScTable::EndListening( const ScAddress& rAddress, SvtListener* pListener )
+{
+ aCol[rAddress.Col()].EndListening( *pListener, rAddress.Row() );
+}
+
+void ScTable::SetPageStyle( const String& rName )
+{
+ if ( aPageStyle != rName )
+ {
+ String aStrNew = rName;
+ SfxStyleSheetBasePool* pStylePool = pDocument->GetStyleSheetPool();
+ SfxStyleSheetBase* pNewStyle = pStylePool->Find( aStrNew, SFX_STYLE_FAMILY_PAGE );
+
+ if ( !pNewStyle )
+ {
+ aStrNew = ScGlobal::GetRscString(STR_STYLENAME_STANDARD);
+ pNewStyle = pStylePool->Find( aStrNew, SFX_STYLE_FAMILY_PAGE );
+ }
+
+ if ( aPageStyle != aStrNew )
+ {
+ SfxStyleSheetBase* pOldStyle = pStylePool->Find( aPageStyle, SFX_STYLE_FAMILY_PAGE );
+
+ if ( pOldStyle && pNewStyle )
+ {
+ SfxItemSet& rOldSet = pOldStyle->GetItemSet();
+ SfxItemSet& rNewSet = pNewStyle->GetItemSet();
+ const USHORT nOldScale = GET_SCALEVALUE(rOldSet,ATTR_PAGE_SCALE);
+ const USHORT nOldScaleToPages = GET_SCALEVALUE(rOldSet,ATTR_PAGE_SCALETOPAGES);
+ const USHORT nNewScale = GET_SCALEVALUE(rNewSet,ATTR_PAGE_SCALE);
+ const USHORT nNewScaleToPages = GET_SCALEVALUE(rNewSet,ATTR_PAGE_SCALETOPAGES);
+
+ if ( (nOldScale != nNewScale) || (nOldScaleToPages != nNewScaleToPages) )
+ InvalidateTextWidth(NULL, NULL, FALSE, FALSE);
+ }
+
+ if ( pNewStyle ) // auch ohne den alten (fuer UpdateStdNames)
+ aPageStyle = aStrNew;
+ }
+ }
+}
+
+void ScTable::PageStyleModified( const String& rNewName )
+{
+ aPageStyle = rNewName;
+ InvalidateTextWidth(NULL, NULL, FALSE, FALSE); // don't know what was in the style before
+}
+
+void ScTable::InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo,
+ BOOL bNumFormatChanged, BOOL bBroadcast )
+{
+ if ( pAdrFrom && !pAdrTo )
+ {
+ ScBaseCell* pCell = aCol[pAdrFrom->Col()].GetCell( pAdrFrom->Row() );
+ if ( pCell )
+ {
+ pCell->SetTextWidth( TEXTWIDTH_DIRTY );
+ if ( bNumFormatChanged )
+ pCell->SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
+ if ( bBroadcast )
+ { // nur bei CalcAsShown
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ pDocument->Broadcast( SC_HINT_DATACHANGED,
+ ScAddress( pAdrFrom->Col(), pAdrFrom->Row(), nTab ),
+ pCell );
+ break;
+ case CELLTYPE_FORMULA :
+ ((ScFormulaCell*)pCell)->SetDirty();
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ const SCCOL nColStart = pAdrFrom ? pAdrFrom->Col() : 0;
+ const SCROW nRowStart = pAdrFrom ? pAdrFrom->Row() : 0;
+ const SCCOL nColEnd = pAdrTo ? pAdrTo->Col() : MAXCOL;
+ const SCROW nRowEnd = pAdrTo ? pAdrTo->Row() : MAXROW;
+
+ for ( SCCOL nCol=nColStart; nCol<=nColEnd; nCol++ )
+ {
+ ScColumnIterator aIter( &aCol[nCol], nRowStart, nRowEnd );
+ ScBaseCell* pCell = NULL;
+ SCROW nRow = nRowStart;
+
+ while ( aIter.Next( nRow, pCell ) )
+ {
+ pCell->SetTextWidth( TEXTWIDTH_DIRTY );
+ if ( bNumFormatChanged )
+ pCell->SetScriptType( SC_SCRIPTTYPE_UNKNOWN );
+ if ( bBroadcast )
+ { // nur bei CalcAsShown
+ switch ( pCell->GetCellType() )
+ {
+ case CELLTYPE_VALUE :
+ pDocument->Broadcast( SC_HINT_DATACHANGED,
+ ScAddress( nCol, nRow, nTab ), pCell );
+ break;
+ case CELLTYPE_FORMULA :
+ ((ScFormulaCell*)pCell)->SetDirty();
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+
+
diff --git a/sc/source/core/data/table6.cxx b/sc/source/core/data/table6.cxx
new file mode 100644
index 000000000000..443d0f23e3d0
--- /dev/null
+++ b/sc/source/core/data/table6.cxx
@@ -0,0 +1,693 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: table6.cxx,v $
+ * $Revision: 1.18.128.3 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include <com/sun/star/i18n/TransliterationModules.hpp>
+
+#include <unotools/textsearch.hxx>
+#include <svx/srchitem.hxx>
+#include <svx/editobj.hxx>
+
+#include "table.hxx"
+#include "collect.hxx"
+#include "cell.hxx"
+#include "document.hxx"
+#include "stlpool.hxx"
+#include "markdata.hxx"
+#include "editutil.hxx"
+#include "detfunc.hxx"
+#include "postit.hxx"
+
+//--------------------------------------------------------------------------
+
+
+BOOL lcl_GetTextWithBreaks( const ScEditCell& rCell, ScDocument* pDoc, String& rVal )
+{
+ // TRUE = more than 1 paragraph
+
+ const EditTextObject* pData = NULL;
+ rCell.GetData( pData );
+ EditEngine& rEngine = pDoc->GetEditEngine();
+ rEngine.SetText( *pData );
+ rVal = rEngine.GetText( LINEEND_LF );
+ return ( rEngine.GetParagraphCount() > 1 );
+}
+
+BOOL ScTable::SearchCell(const SvxSearchItem& rSearchItem, SCCOL nCol, SCROW nRow,
+ const ScMarkData& rMark, String& rUndoStr, ScDocument* pUndoDoc)
+{
+ BOOL bFound = FALSE;
+ BOOL bDoSearch = TRUE;
+ BOOL bDoBack = rSearchItem.GetBackward();
+
+ String aString;
+ ScBaseCell* pCell;
+ if (rSearchItem.GetSelection())
+ bDoSearch = rMark.IsCellMarked(nCol, nRow);
+ if ( bDoSearch && ((pCell = aCol[nCol].GetCell( nRow )) != NULL) )
+ {
+ BOOL bMultiLine = FALSE;
+ CellType eCellType = pCell->GetCellType();
+ switch (rSearchItem.GetCellType())
+ {
+ case SVX_SEARCHIN_FORMULA:
+ {
+ if ( eCellType == CELLTYPE_FORMULA )
+ ((ScFormulaCell*)pCell)->GetFormula( aString,
+ formula::FormulaGrammar::GRAM_NATIVE_UI);
+ else if ( eCellType == CELLTYPE_EDIT )
+ bMultiLine = lcl_GetTextWithBreaks(
+ *(const ScEditCell*)pCell, pDocument, aString );
+ else
+ aCol[nCol].GetInputString( nRow, aString );
+ }
+ break;
+ case SVX_SEARCHIN_VALUE:
+ if ( eCellType == CELLTYPE_EDIT )
+ bMultiLine = lcl_GetTextWithBreaks(
+ *(const ScEditCell*)pCell, pDocument, aString );
+ else
+ aCol[nCol].GetInputString( nRow, aString );
+ break;
+ case SVX_SEARCHIN_NOTE:
+ {
+ if(const ScPostIt* pNote = pCell->GetNote())
+ {
+ aString = pNote->GetText();
+ bMultiLine = pNote->HasMultiLineText();
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ xub_StrLen nStart = 0;
+ xub_StrLen nEnd = aString.Len();
+ ::com::sun::star::util::SearchResult aSearchResult;
+ if (pSearchText)
+ {
+ if ( bDoBack )
+ {
+ xub_StrLen nTemp=nStart; nStart=nEnd; nEnd=nTemp;
+ bFound = (BOOL)(pSearchText->SearchBkwrd(aString, &nStart, &nEnd, &aSearchResult));
+ // change results to definition before 614:
+ --nEnd;
+ }
+ else
+ {
+ bFound = (BOOL)(pSearchText->SearchFrwrd(aString, &nStart, &nEnd, &aSearchResult));
+ // change results to definition before 614:
+ --nEnd;
+ }
+
+ if (bFound && rSearchItem.GetWordOnly())
+ bFound = (nStart == 0 && nEnd == aString.Len() - 1);
+ }
+ else
+ {
+ DBG_ERROR("pSearchText == NULL");
+ return bFound;
+ }
+
+ BYTE cMatrixFlag = MM_NONE;
+ if ( bFound &&
+ ( (rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE)
+ ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL) ) &&
+ // #60558# Matrix nicht zerreissen, nur Matrixformel ersetzen
+ !( (eCellType == CELLTYPE_FORMULA &&
+ ((cMatrixFlag = ((ScFormulaCell*)pCell)->GetMatrixFlag()) == MM_REFERENCE))
+ // kein UndoDoc => Matrix nicht wiederherstellbar => nicht ersetzen
+ || (cMatrixFlag != MM_NONE && !pUndoDoc) )
+ )
+ {
+ if ( cMatrixFlag == MM_NONE && rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE )
+ rUndoStr = aString;
+ else if (pUndoDoc)
+ {
+ ScAddress aAdr( nCol, nRow, nTab );
+ ScBaseCell* pUndoCell = pCell->CloneWithoutNote( *pUndoDoc );
+ pUndoDoc->PutCell( aAdr, pUndoCell);
+ }
+ BOOL bRepeat = !rSearchItem.GetWordOnly();
+ do
+ {
+ // wenn der gefundene Text leer ist, nicht weitersuchen,
+ // sonst wuerde man nie mehr aufhoeren (#35410#)
+ if ( nEnd < nStart || nEnd == STRING_MAXLEN )
+ bRepeat = FALSE;
+
+ String sReplStr = rSearchItem.GetReplaceString();
+ if (rSearchItem.GetRegExp())
+ {
+ String sFndStr = aString.Copy(nStart, nEnd-nStart+1);
+ pSearchText->ReplaceBackReferences( sReplStr, aString, aSearchResult );
+ aString.Erase(nStart, nEnd-nStart+1);
+ aString.Insert(sReplStr, nStart);
+ }
+ else
+ {
+ aString.Erase(nStart, nEnd - nStart + 1);
+ aString.Insert(rSearchItem.GetReplaceString(), nStart);
+ }
+
+ // Indizes anpassen
+ if (bDoBack)
+ {
+ nEnd = nStart;
+ nStart = 0;
+ }
+ else
+ {
+ nStart = sal::static_int_cast<xub_StrLen>( nStart + sReplStr.Len() );
+ nEnd = aString.Len();
+ }
+
+ // weitersuchen ?
+ if (bRepeat)
+ {
+ if ( rSearchItem.GetCommand() != SVX_SEARCHCMD_REPLACE_ALL || nStart >= nEnd )
+ bRepeat = FALSE;
+ else if (bDoBack)
+ {
+ xub_StrLen nTemp=nStart; nStart=nEnd; nEnd=nTemp;
+ bRepeat = ((BOOL)(pSearchText->SearchBkwrd(aString, &nStart, &nEnd)));
+ // change results to definition before 614:
+ --nEnd;
+ }
+ else
+ {
+ bRepeat = ((BOOL)(pSearchText->SearchFrwrd(aString, &nStart, &nEnd)));
+ // change results to definition before 614:
+ --nEnd;
+ }
+ }
+ }
+ while (bRepeat);
+ if (rSearchItem.GetCellType() == SVX_SEARCHIN_NOTE)
+ {
+ // NB: rich text format is lost.
+ // This is also true of Cells.
+ if( ScPostIt* pNote = pCell->GetNote() )
+ pNote->SetText( aString );
+ }
+ else if ( cMatrixFlag != MM_NONE )
+ { // #60558# Matrix nicht zerreissen
+ if ( aString.Len() > 2 )
+ { // {} raus, erst hier damit auch "{=" durch "{=..." ersetzt werden kann
+ if ( aString.GetChar( aString.Len()-1 ) == '}' )
+ aString.Erase( aString.Len()-1, 1 );
+ if ( aString.GetChar(0) == '{' )
+ aString.Erase( 0, 1 );
+ }
+ ScAddress aAdr( nCol, nRow, nTab );
+ ScFormulaCell* pFCell = new ScFormulaCell( pDocument, aAdr,
+ aString,formula::FormulaGrammar::GRAM_NATIVE_UI, cMatrixFlag );
+ SCCOL nMatCols;
+ SCROW nMatRows;
+ ((ScFormulaCell*)pCell)->GetMatColsRows( nMatCols, nMatRows );
+ pFCell->SetMatColsRows( nMatCols, nMatRows );
+ aCol[nCol].Insert( nRow, pFCell );
+ }
+ else if ( bMultiLine && aString.Search('\n') != STRING_NOTFOUND )
+ PutCell( nCol, nRow, new ScEditCell( aString, pDocument ) );
+ else
+ aCol[nCol].SetString(nRow, nTab, aString);
+ // pCell is invalid now (deleted)
+ }
+ }
+ return bFound;
+}
+
+BOOL ScTable::Search(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
+ const ScMarkData& rMark, String& rUndoStr, ScDocument* pUndoDoc)
+{
+ BOOL bFound = FALSE;
+ BOOL bAll = (rSearchItem.GetCommand() == SVX_SEARCHCMD_FIND_ALL)
+ ||(rSearchItem.GetCommand() == SVX_SEARCHCMD_REPLACE_ALL);
+ SCCOL nCol = rCol;
+ SCROW nRow = rRow;
+ SCCOL nLastCol;
+ SCROW nLastRow;
+ GetLastDataPos(nLastCol, nLastRow);
+ if (!bAll && rSearchItem.GetBackward())
+ {
+ nCol = Min(nCol, (SCCOL)(nLastCol + 1));
+ nRow = Min(nRow, (SCROW)(nLastRow + 1));
+ if (rSearchItem.GetRowDirection())
+ {
+ nCol--;
+ while (!bFound && ((SCsROW)nRow >= 0))
+ {
+ while (!bFound && ((SCsCOL)nCol >= 0))
+ {
+ bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
+ if (!bFound)
+ {
+ BOOL bIsEmpty;
+ do
+ {
+ nCol--;
+ if ((SCsCOL)nCol >= 0)
+ bIsEmpty = aCol[nCol].IsEmptyData();
+ else
+ bIsEmpty = TRUE;
+ }
+ while (((SCsCOL)nCol >= 0) && bIsEmpty);
+ }
+ }
+ if (!bFound)
+ {
+ nCol = nLastCol;
+ nRow--;
+ }
+ }
+ }
+ else
+ {
+ nRow--;
+ while (!bFound && ((SCsCOL)nCol >= 0))
+ {
+ while (!bFound && ((SCsROW)nRow >= 0))
+ {
+ bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
+ if (!bFound)
+ {
+ if (!aCol[nCol].GetPrevDataPos(nRow))
+ nRow = -1;
+ }
+ }
+ if (!bFound)
+ {
+ BOOL bIsEmpty;
+ nRow = nLastRow;
+ do
+ {
+ nCol--;
+ if ((SCsCOL)nCol >= 0)
+ bIsEmpty = aCol[nCol].IsEmptyData();
+ else
+ bIsEmpty = TRUE;
+ }
+ while (((SCsCOL)nCol >= 0) && bIsEmpty);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (!bAll && rSearchItem.GetRowDirection())
+ {
+ nCol++;
+ while (!bFound && (nRow <= nLastRow))
+ {
+ while (!bFound && (nCol <= nLastCol))
+ {
+ bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
+ if (!bFound)
+ {
+ nCol++;
+ while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
+ }
+ }
+ if (!bFound)
+ {
+ nCol = 0;
+ nRow++;
+ }
+ }
+ }
+ else
+ {
+ nRow++;
+ while (!bFound && (nCol <= nLastCol))
+ {
+ while (!bFound && (nRow <= nLastRow))
+ {
+ bFound = SearchCell(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
+ if (!bFound)
+ {
+ if (!aCol[nCol].GetNextDataPos(nRow))
+ nRow = MAXROW + 1;
+ }
+ }
+ if (!bFound)
+ {
+ nRow = 0;
+ nCol++;
+ while ((nCol <= nLastCol) && aCol[nCol].IsEmptyData()) nCol++;
+ }
+ }
+ }
+ }
+ if (bFound)
+ {
+ rCol = nCol;
+ rRow = nRow;
+ }
+ return bFound;
+}
+
+BOOL ScTable::SearchAll(const SvxSearchItem& rSearchItem, ScMarkData& rMark,
+ String& rUndoStr, ScDocument* pUndoDoc)
+{
+ BOOL bFound = TRUE;
+ SCCOL nCol = 0;
+ SCROW nRow = -1;
+
+ ScMarkData aNewMark( rMark ); // Tabellen-Markierungen kopieren
+ aNewMark.ResetMark();
+ do
+ {
+ bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
+ if (bFound)
+ aNewMark.SetMultiMarkArea( ScRange( nCol, nRow, nTab ) );
+ }
+ while (bFound);
+
+ rMark = aNewMark; // Markierung kopieren
+ //! pro Tabelle
+
+ return (aNewMark.IsMultiMarked());
+}
+
+BOOL ScTable::Replace(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
+ const ScMarkData& rMark, String& rUndoStr, ScDocument* pUndoDoc)
+{
+ BOOL bFound = FALSE;
+ SCCOL nCol = rCol;
+ SCROW nRow = rRow;
+ if (rSearchItem.GetBackward())
+ {
+ if (rSearchItem.GetRowDirection())
+ nCol += 1;
+ else
+ nRow += 1;
+ }
+ else
+ {
+ if (rSearchItem.GetRowDirection())
+ nCol -= 1;
+ else
+ nRow -= 1;
+ }
+ bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
+ if (bFound)
+ {
+ rCol = nCol;
+ rRow = nRow;
+ }
+ return bFound;
+}
+
+BOOL ScTable::ReplaceAll(const SvxSearchItem& rSearchItem, ScMarkData& rMark,
+ String& rUndoStr, ScDocument* pUndoDoc)
+{
+ BOOL bOldDouble = ScColumn::bDoubleAlloc; // sollte immer FALSE sein?
+ DBG_ASSERT(!bOldDouble,"bDoubleAlloc ???");
+ ScColumn::bDoubleAlloc = TRUE; // fuer Undo-Doc
+
+ BOOL bFound = TRUE;
+ SCCOL nCol = 0;
+ SCROW nRow = -1;
+
+ ScMarkData aNewMark( rMark ); // Tabellen-Markierungen kopieren
+ aNewMark.ResetMark();
+ do
+ {
+ bFound = Search(rSearchItem, nCol, nRow, rMark, rUndoStr, pUndoDoc);
+ if (bFound)
+ aNewMark.SetMultiMarkArea( ScRange( nCol, nRow, nTab ) );
+ }
+ while (bFound);
+
+ ScColumn::bDoubleAlloc = bOldDouble;
+
+ rMark = aNewMark; // Markierung kopieren
+ //! pro Tabelle
+
+ return (aNewMark.IsMultiMarked());
+}
+
+BOOL ScTable::SearchStyle(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
+ ScMarkData& rMark)
+{
+ const ScStyleSheet* pSearchStyle = (const ScStyleSheet*)
+ pDocument->GetStyleSheetPool()->Find(
+ rSearchItem.GetSearchString(), SFX_STYLE_FAMILY_PARA );
+
+ SCsCOL nCol = rCol;
+ SCsROW nRow = rRow;
+ BOOL bFound = FALSE;
+
+ BOOL bSelect = rSearchItem.GetSelection();
+ BOOL bRows = rSearchItem.GetRowDirection();
+ BOOL bBack = rSearchItem.GetBackward();
+ short nAdd = bBack ? -1 : 1;
+
+ if (bRows) // zeilenweise
+ {
+ nRow += nAdd;
+ do
+ {
+ SCsROW nNextRow = aCol[nCol].SearchStyle( nRow, pSearchStyle, bBack, bSelect, rMark );
+ if (!ValidRow(nNextRow))
+ {
+ nRow = bBack ? MAXROW : 0;
+ nCol = sal::static_int_cast<SCsCOL>( nCol + nAdd );
+ }
+ else
+ {
+ nRow = nNextRow;
+ bFound = TRUE;
+ }
+ }
+ while (!bFound && ValidCol(nCol));
+ }
+ else // spaltenweise
+ {
+ SCsROW nNextRows[MAXCOLCOUNT];
+ SCsCOL i;
+ for (i=0; i<=MAXCOL; i++)
+ {
+ SCsROW nSRow = nRow;
+ if (bBack) { if (i>=nCol) --nSRow; }
+ else { if (i<=nCol) ++nSRow; }
+ nNextRows[i] = aCol[i].SearchStyle( nSRow, pSearchStyle, bBack, bSelect, rMark );
+ }
+ if (bBack) // rueckwaerts
+ {
+ nRow = -1;
+ for (i=MAXCOL; i>=0; i--)
+ if (nNextRows[i]>nRow)
+ {
+ nCol = i;
+ nRow = nNextRows[i];
+ bFound = TRUE;
+ }
+ }
+ else // vorwaerts
+ {
+ nRow = MAXROW+1;
+ for (i=0; i<=MAXCOL; i++)
+ if (nNextRows[i]<nRow)
+ {
+ nCol = i;
+ nRow = nNextRows[i];
+ bFound = TRUE;
+ }
+ }
+ }
+
+ if (bFound)
+ {
+ rCol = (SCCOL) nCol;
+ rRow = (SCROW) nRow;
+ }
+ return bFound;
+}
+
+//! einzelnes Pattern fuer Undo zurueckgeben
+
+BOOL ScTable::ReplaceStyle(const SvxSearchItem& rSearchItem, SCCOL& rCol, SCROW& rRow,
+ ScMarkData& rMark, BOOL bIsUndo)
+{
+ BOOL bRet;
+ if (bIsUndo)
+ bRet = TRUE;
+ else
+ bRet = SearchStyle(rSearchItem, rCol, rRow, rMark);
+ if (bRet)
+ {
+ const ScStyleSheet* pReplaceStyle = (const ScStyleSheet*)
+ pDocument->GetStyleSheetPool()->Find(
+ rSearchItem.GetReplaceString(), SFX_STYLE_FAMILY_PARA );
+
+ if (pReplaceStyle)
+ ApplyStyle( rCol, rRow, *pReplaceStyle );
+ else
+ {
+ DBG_ERROR("pReplaceStyle==0");
+ }
+ }
+
+ return bRet;
+}
+
+BOOL ScTable::SearchAllStyle(const SvxSearchItem& rSearchItem, ScMarkData& rMark)
+{
+ const ScStyleSheet* pSearchStyle = (const ScStyleSheet*)
+ pDocument->GetStyleSheetPool()->Find(
+ rSearchItem.GetSearchString(), SFX_STYLE_FAMILY_PARA );
+ BOOL bSelect = rSearchItem.GetSelection();
+ BOOL bBack = rSearchItem.GetBackward();
+
+ ScMarkData aNewMark( rMark ); // Tabellen-Markierungen kopieren
+ aNewMark.ResetMark();
+ for (SCCOL i=0; i<=MAXCOL; i++)
+ {
+ BOOL bFound = TRUE;
+ SCsROW nRow = 0;
+ SCsROW nEndRow;
+ while (bFound && nRow <= MAXROW)
+ {
+ bFound = aCol[i].SearchStyleRange( nRow, nEndRow, pSearchStyle, bBack, bSelect, rMark );
+ if (bFound)
+ {
+ if (nEndRow<nRow)
+ {
+ SCsROW nTemp = nRow;
+ nRow = nEndRow;
+ nEndRow = nTemp;
+ }
+ aNewMark.SetMultiMarkArea( ScRange( i,nRow,nTab, i,nEndRow,nTab ) );
+ nRow = nEndRow + 1;
+ }
+ }
+ }
+
+ rMark = aNewMark; // Markierung kopieren
+ //! pro Tabelle
+
+ return (aNewMark.IsMultiMarked());
+}
+
+BOOL ScTable::ReplaceAllStyle(const SvxSearchItem& rSearchItem, ScMarkData& rMark,
+ ScDocument* pUndoDoc)
+{
+ BOOL bRet = SearchAllStyle(rSearchItem, rMark);
+ if (bRet)
+ {
+ const ScStyleSheet* pReplaceStyle = (const ScStyleSheet*)
+ pDocument->GetStyleSheetPool()->Find(
+ rSearchItem.GetReplaceString(), SFX_STYLE_FAMILY_PARA );
+
+ if (pReplaceStyle)
+ {
+ if (pUndoDoc)
+ pDocument->CopyToDocument( 0,0,nTab, MAXCOL,MAXROW,nTab,
+ IDF_ATTRIB, TRUE, pUndoDoc, &rMark );
+ ApplySelectionStyle( *pReplaceStyle, rMark );
+ }
+ else
+ {
+ DBG_ERROR("pReplaceStyle==0");
+ }
+ }
+
+ return bRet;
+}
+
+BOOL ScTable::SearchAndReplace(const SvxSearchItem& rSearchItem,
+ SCCOL& rCol, SCROW& rRow, ScMarkData& rMark,
+ String& rUndoStr, ScDocument* pUndoDoc)
+{
+ USHORT nCommand = rSearchItem.GetCommand();
+ BOOL bFound = FALSE;
+ if ( ValidColRow(rCol, rRow) ||
+ ((nCommand == SVX_SEARCHCMD_FIND || nCommand == SVX_SEARCHCMD_REPLACE) &&
+ (((rCol == MAXCOLCOUNT || rCol == -1) && VALIDROW(rRow)) ||
+ ((rRow == MAXROWCOUNT || rRow == -1) && VALIDCOL(rCol))
+ )
+ )
+ )
+ {
+ BOOL bStyles = rSearchItem.GetPattern();
+ if (bStyles)
+ {
+ if (nCommand == SVX_SEARCHCMD_FIND)
+ bFound = SearchStyle(rSearchItem, rCol, rRow, rMark);
+ else if (nCommand == SVX_SEARCHCMD_REPLACE)
+ bFound = ReplaceStyle(rSearchItem, rCol, rRow, rMark, FALSE);
+ else if (nCommand == SVX_SEARCHCMD_FIND_ALL)
+ bFound = SearchAllStyle(rSearchItem, rMark);
+ else if (nCommand == SVX_SEARCHCMD_REPLACE_ALL)
+ bFound = ReplaceAllStyle(rSearchItem, rMark, pUndoDoc);
+ }
+ else
+ {
+ // SearchParam no longer needed - SearchOptions contains all settings
+ com::sun::star::util::SearchOptions aSearchOptions = rSearchItem.GetSearchOptions();
+ aSearchOptions.Locale = *ScGlobal::pLocale;
+
+ // #107259# reflect UseAsianOptions flag in SearchOptions
+ // (use only ignore case and width if asian options are disabled).
+ // This is also done in SvxSearchDialog CommandHdl, but not in API object.
+ if ( !rSearchItem.IsUseAsianOptions() )
+ aSearchOptions.transliterateFlags &=
+ ( com::sun::star::i18n::TransliterationModules_IGNORE_CASE |
+ com::sun::star::i18n::TransliterationModules_IGNORE_WIDTH );
+
+ pSearchText = new utl::TextSearch( aSearchOptions );
+
+ if (nCommand == SVX_SEARCHCMD_FIND)
+ bFound = Search(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
+ else if (nCommand == SVX_SEARCHCMD_FIND_ALL)
+ bFound = SearchAll(rSearchItem, rMark, rUndoStr, pUndoDoc);
+ else if (nCommand == SVX_SEARCHCMD_REPLACE)
+ bFound = Replace(rSearchItem, rCol, rRow, rMark, rUndoStr, pUndoDoc);
+ else if (nCommand == SVX_SEARCHCMD_REPLACE_ALL)
+ bFound = ReplaceAll(rSearchItem, rMark, rUndoStr, pUndoDoc);
+
+ delete pSearchText;
+ pSearchText = NULL;
+ }
+ }
+ return bFound;
+}
+
+
+
+
+
+
diff --git a/sc/source/core/data/userdat.cxx b/sc/source/core/data/userdat.cxx
new file mode 100644
index 000000000000..66397700676c
--- /dev/null
+++ b/sc/source/core/data/userdat.cxx
@@ -0,0 +1,130 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: userdat.cxx,v $
+ * $Revision: 1.12.128.1 $
+ *
+ * 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 "userdat.hxx"
+#include <tools/debug.hxx>
+#include "drwlayer.hxx"
+#include "rechead.hxx"
+
+// -----------------------------------------------------------------------
+
+ScDrawObjFactory::ScDrawObjFactory()
+{
+ SdrObjFactory::InsertMakeUserDataHdl( LINK ( this, ScDrawObjFactory, MakeUserData ) );
+}
+
+ScDrawObjFactory::~ScDrawObjFactory()
+{
+ SdrObjFactory::RemoveMakeUserDataHdl( LINK ( this, ScDrawObjFactory, MakeUserData ) );
+}
+
+IMPL_LINK_INLINE_START( ScDrawObjFactory, MakeUserData, SdrObjFactory *, pObjFactory )
+{
+ if ( pObjFactory->nInventor == SC_DRAWLAYER )
+ {
+ if ( pObjFactory->nIdentifier == SC_UD_OBJDATA )
+ pObjFactory->pNewData = new ScDrawObjData;
+ else if ( pObjFactory->nIdentifier == SC_UD_IMAPDATA )
+ pObjFactory->pNewData = new ScIMapInfo;
+ else if ( pObjFactory->nIdentifier == SC_UD_MACRODATA )
+ pObjFactory->pNewData = new ScMacroInfo;
+ else
+ {
+ DBG_ERROR("MakeUserData: falsche ID");
+ }
+ }
+ return 0;
+}
+IMPL_LINK_INLINE_END( ScDrawObjFactory, MakeUserData, SdrObjFactory *, pObjFactory )
+
+//------------------------------------------------------------------------
+
+ScDrawObjData::ScDrawObjData() :
+ SdrObjUserData( SC_DRAWLAYER, SC_UD_OBJDATA, 0 ),
+ maStart( ScAddress::INITIALIZE_INVALID ),
+ maEnd( ScAddress::INITIALIZE_INVALID ),
+ mbNote( false )
+{
+}
+
+ScDrawObjData* ScDrawObjData::Clone( SdrObject* ) const
+{
+ return new ScDrawObjData( *this );
+}
+
+//------------------------------------------------------------------------
+
+ScIMapInfo::ScIMapInfo() :
+ SdrObjUserData( SC_DRAWLAYER, SC_UD_IMAPDATA, 0 )
+{
+}
+
+ScIMapInfo::ScIMapInfo( const ImageMap& rImageMap ) :
+ SdrObjUserData( SC_DRAWLAYER, SC_UD_IMAPDATA, 0 ),
+ aImageMap( rImageMap )
+{
+}
+
+ScIMapInfo::ScIMapInfo( const ScIMapInfo& rIMapInfo ) :
+ SdrObjUserData( rIMapInfo ),
+ aImageMap( rIMapInfo.aImageMap )
+{
+}
+
+ScIMapInfo::~ScIMapInfo()
+{
+}
+
+SdrObjUserData* ScIMapInfo::Clone( SdrObject* ) const
+{
+ return new ScIMapInfo( *this );
+}
+
+//------------------------------------------------------------------------
+
+ScMacroInfo::ScMacroInfo() :
+ SdrObjUserData( SC_DRAWLAYER, SC_UD_MACRODATA, 0 )
+{
+}
+
+ScMacroInfo::~ScMacroInfo()
+{
+}
+
+SdrObjUserData* ScMacroInfo::Clone( SdrObject* /*pObj*/ ) const
+{
+ return new ScMacroInfo( *this );
+}
+
diff --git a/sc/source/core/data/validat.cxx b/sc/source/core/data/validat.cxx
new file mode 100644
index 000000000000..09c1db07c464
--- /dev/null
+++ b/sc/source/core/data/validat.cxx
@@ -0,0 +1,963 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2008 by Sun Microsystems, Inc.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: validat.cxx,v $
+ * $Revision: 1.24.110.2 $
+ *
+ * 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 ---------------------------------------------------------------
+
+#include "scitems.hxx"
+#include <sfx2/app.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <basic/sbmeth.hxx>
+#include <basic/sbmod.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/basmgr.hxx>
+
+#include <basic/sbx.hxx>
+#include <svtools/zforlist.hxx>
+#include <vcl/msgbox.hxx>
+#include <tools/urlobj.hxx>
+#include <rtl/math.hxx>
+
+#include "validat.hxx"
+#include "document.hxx"
+#include "cell.hxx"
+#include "patattr.hxx"
+#include "rechead.hxx"
+#include "globstr.hrc"
+#include "rangenam.hxx"
+#include "dbcolect.hxx"
+
+#include <math.h>
+#include <memory>
+
+using namespace formula;
+//------------------------------------------------------------------------
+
+SV_IMPL_OP_PTRARR_SORT( ScValidationEntries_Impl, ScValidationDataPtr );
+
+//------------------------------------------------------------------------
+
+//
+// Eintrag fuer Gueltigkeit (es gibt nur eine Bedingung)
+//
+
+ScValidationData::ScValidationData( ScValidationMode eMode, ScConditionMode eOper,
+ const String& rExpr1, const String& rExpr2,
+ ScDocument* pDocument, const ScAddress& rPos,
+ const formula::FormulaGrammar::Grammar eGrammar ) :
+ ScConditionEntry( eOper, rExpr1, rExpr2, pDocument, rPos, eGrammar ),
+ nKey( 0 ),
+ eDataMode( eMode ),
+ eErrorStyle( SC_VALERR_STOP ),
+ mnListType( ValidListType::UNSORTED )
+{
+ bShowInput = bShowError = FALSE;
+}
+
+ScValidationData::ScValidationData( ScValidationMode eMode, ScConditionMode eOper,
+ const ScTokenArray* pArr1, const ScTokenArray* pArr2,
+ ScDocument* pDocument, const ScAddress& rPos ) :
+ ScConditionEntry( eOper, pArr1, pArr2, pDocument, rPos ),
+ nKey( 0 ),
+ eDataMode( eMode ),
+ eErrorStyle( SC_VALERR_STOP ),
+ mnListType( ValidListType::UNSORTED )
+{
+ bShowInput = bShowError = FALSE;
+}
+
+ScValidationData::ScValidationData( const ScValidationData& r ) :
+ ScConditionEntry( r ),
+ nKey( r.nKey ),
+ eDataMode( r.eDataMode ),
+ bShowInput( r.bShowInput ),
+ bShowError( r.bShowError ),
+ eErrorStyle( r.eErrorStyle ),
+ mnListType( r.mnListType ),
+ aInputTitle( r.aInputTitle ),
+ aInputMessage( r.aInputMessage ),
+ aErrorTitle( r.aErrorTitle ),
+ aErrorMessage( r.aErrorMessage )
+{
+ // Formeln per RefCount kopiert
+}
+
+ScValidationData::ScValidationData( ScDocument* pDocument, const ScValidationData& r ) :
+ ScConditionEntry( pDocument, r ),
+ nKey( r.nKey ),
+ eDataMode( r.eDataMode ),
+ bShowInput( r.bShowInput ),
+ bShowError( r.bShowError ),
+ eErrorStyle( r.eErrorStyle ),
+ mnListType( r.mnListType ),
+ aInputTitle( r.aInputTitle ),
+ aInputMessage( r.aInputMessage ),
+ aErrorTitle( r.aErrorTitle ),
+ aErrorMessage( r.aErrorMessage )
+{
+ // Formeln wirklich kopiert
+}
+
+ScValidationData::~ScValidationData()
+{
+}
+
+BOOL ScValidationData::IsEmpty() const
+{
+ String aEmpty;
+ ScValidationData aDefault( SC_VALID_ANY, SC_COND_EQUAL, aEmpty, aEmpty, GetDocument(), ScAddress() );
+ return EqualEntries( aDefault );
+}
+
+BOOL ScValidationData::EqualEntries( const ScValidationData& r ) const
+{
+ // gleiche Parameter eingestellt (ohne Key)
+
+ return ScConditionEntry::operator==(r) &&
+ eDataMode == r.eDataMode &&
+ bShowInput == r.bShowInput &&
+ bShowError == r.bShowError &&
+ eErrorStyle == r.eErrorStyle &&
+ mnListType == r.mnListType &&
+ aInputTitle == r.aInputTitle &&
+ aInputMessage == r.aInputMessage &&
+ aErrorTitle == r.aErrorTitle &&
+ aErrorMessage == r.aErrorMessage;
+}
+
+void ScValidationData::ResetInput()
+{
+ bShowInput = FALSE;
+}
+
+void ScValidationData::ResetError()
+{
+ bShowError = FALSE;
+}
+
+void ScValidationData::SetInput( const String& rTitle, const String& rMsg )
+{
+ bShowInput = TRUE;
+ aInputTitle = rTitle;
+ aInputMessage = rMsg;
+}
+
+void ScValidationData::SetError( const String& rTitle, const String& rMsg,
+ ScValidErrorStyle eStyle )
+{
+ bShowError = TRUE;
+ eErrorStyle = eStyle;
+ aErrorTitle = rTitle;
+ aErrorMessage = rMsg;
+}
+
+BOOL ScValidationData::GetErrMsg( String& rTitle, String& rMsg,
+ ScValidErrorStyle& rStyle ) const
+{
+ rTitle = aErrorTitle;
+ rMsg = aErrorMessage;
+ rStyle = eErrorStyle;
+ return bShowError;
+}
+
+BOOL ScValidationData::DoScript( const ScAddress& rPos, const String& rInput,
+ ScFormulaCell* pCell, Window* pParent ) const
+{
+ ScDocument* pDocument = GetDocument();
+ SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
+ if ( !pDocSh || !pDocument->CheckMacroWarn() )
+ return FALSE;
+
+ BOOL bScriptReturnedFalse = FALSE; // Standard: kein Abbruch
+
+ // Set up parameters
+ ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > aParams(2);
+
+ // 1) eingegebener / berechneter Wert
+ String aValStr = rInput;
+ double nValue;
+ BOOL bIsValue = FALSE;
+ if ( pCell ) // wenn Zelle gesetzt, aus Interpret gerufen
+ {
+ bIsValue = pCell->IsValue();
+ if ( bIsValue )
+ nValue = pCell->GetValue();
+ else
+ pCell->GetString( aValStr );
+ }
+ if ( bIsValue )
+ aParams[0] = ::com::sun::star::uno::makeAny( nValue );
+ else
+ aParams[0] = ::com::sun::star::uno::makeAny( ::rtl::OUString( aValStr ) );
+
+ // 2) Position der Zelle
+ String aPosStr;
+ rPos.Format( aPosStr, SCA_VALID | SCA_TAB_3D, pDocument, pDocument->GetAddressConvention() );
+ aParams[1] = ::com::sun::star::uno::makeAny( ::rtl::OUString( aPosStr ) );
+
+ // use link-update flag to prevent closing the document
+ // while the macro is running
+ BOOL bWasInLinkUpdate = pDocument->IsInLinkUpdate();
+ if ( !bWasInLinkUpdate )
+ pDocument->SetInLinkUpdate( TRUE );
+
+ if ( pCell )
+ pDocument->LockTable( rPos.Tab() );
+
+ ::com::sun::star::uno::Any aRet;
+ ::com::sun::star::uno::Sequence< sal_Int16 > aOutArgsIndex;
+ ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Any > aOutArgs;
+
+ ErrCode eRet = pDocSh->CallXScript(
+ aErrorTitle, aParams, aRet, aOutArgsIndex, aOutArgs );
+
+ if ( pCell )
+ pDocument->UnlockTable( rPos.Tab() );
+
+ if ( !bWasInLinkUpdate )
+ pDocument->SetInLinkUpdate( FALSE );
+
+ // Check the return value from the script
+ // The contents of the cell get reset if the script returns false
+ BOOL bTmp = FALSE;
+ if ( eRet == ERRCODE_NONE &&
+ aRet.getValueType() == getCppuBooleanType() &&
+ sal_True == ( aRet >>= bTmp ) &&
+ bTmp == FALSE )
+ {
+ bScriptReturnedFalse = TRUE;
+ }
+
+ if ( eRet == ERRCODE_BASIC_METHOD_NOT_FOUND && !pCell )
+ // Makro nicht gefunden (nur bei Eingabe)
+ {
+ //! andere Fehlermeldung, wenn gefunden, aber nicht bAllowed ??
+
+ ErrorBox aBox( pParent, WinBits(WB_OK),
+ ScGlobal::GetRscString( STR_VALID_MACRONOTFOUND ) );
+ aBox.Execute();
+ }
+
+ return bScriptReturnedFalse;
+}
+
+ // TRUE -> Abbruch
+
+BOOL ScValidationData::DoMacro( const ScAddress& rPos, const String& rInput,
+ ScFormulaCell* pCell, Window* pParent ) const
+{
+ if ( SfxApplication::IsXScriptURL( aErrorTitle ) )
+ {
+ return DoScript( rPos, rInput, pCell, pParent );
+ }
+
+ ScDocument* pDocument = GetDocument();
+ SfxObjectShell* pDocSh = pDocument->GetDocumentShell();
+ if ( !pDocSh || !pDocument->CheckMacroWarn() )
+ return FALSE;
+
+ BOOL bDone = FALSE;
+ BOOL bRet = FALSE; // Standard: kein Abbruch
+ SfxApplication* pSfxApp = SFX_APP();
+ pSfxApp->EnterBasicCall(); // Dok-Basic anlegen etc.
+
+ // Wenn das Dok waehrend eines Basic-Calls geladen wurde,
+ // ist das Sbx-Objekt evtl. nicht angelegt (?)
+// pDocSh->GetSbxObject();
+
+ // keine Sicherheitsabfrage mehr vorneweg (nur CheckMacroWarn), das passiert im CallBasic
+
+#if 0
+ // Makro-Name liegt in folgender Form vor:
+ // "Macroname.Modulname.Libname.Dokumentname" oder
+ // "Macroname.Modulname.Libname.Applikationsname"
+ String aMacroName = aErrorTitle.GetToken(0, '.');
+ String aModulName = aErrorTitle.GetToken(1, '.');
+ String aLibName = aErrorTitle.GetToken(2, '.');
+ String aDocName = aErrorTitle.GetToken(3, '.');
+#endif
+
+ // Funktion ueber den einfachen Namen suchen,
+ // dann aBasicStr, aMacroStr fuer SfxObjectShell::CallBasic zusammenbauen
+
+ StarBASIC* pRoot = pDocSh->GetBasic();
+ SbxVariable* pVar = pRoot->Find( aErrorTitle, SbxCLASS_METHOD );
+ if ( pVar && pVar->ISA(SbMethod) )
+ {
+ SbMethod* pMethod = (SbMethod*)pVar;
+ SbModule* pModule = pMethod->GetModule();
+ SbxObject* pObject = pModule->GetParent();
+ String aMacroStr = pObject->GetName();
+ aMacroStr += '.';
+ aMacroStr += pModule->GetName();
+ aMacroStr += '.';
+ aMacroStr += pMethod->GetName();
+ String aBasicStr;
+
+ // #95867# the distinction between document- and app-basic has to be done
+ // by checking the parent (as in ScInterpreter::ScMacro), not by looping
+ // over all open documents, because this may be called from within loading,
+ // when SfxObjectShell::GetFirst/GetNext won't find the document.
+
+ if ( pObject->GetParent() )
+ aBasicStr = pObject->GetParent()->GetName(); // Dokumentenbasic
+ else
+ aBasicStr = SFX_APP()->GetName(); // Applikationsbasic
+
+ // Parameter fuer Makro
+ SbxArrayRef refPar = new SbxArray;
+
+ // 1) eingegebener / berechneter Wert
+ String aValStr = rInput;
+ double nValue = 0.0;
+ BOOL bIsValue = FALSE;
+ if ( pCell ) // wenn Zelle gesetzt, aus Interpret gerufen
+ {
+ bIsValue = pCell->IsValue();
+ if ( bIsValue )
+ nValue = pCell->GetValue();
+ else
+ pCell->GetString( aValStr );
+ }
+ if ( bIsValue )
+ refPar->Get(1)->PutDouble( nValue );
+ else
+ refPar->Get(1)->PutString( aValStr );
+
+ // 2) Position der Zelle
+ String aPosStr;
+ rPos.Format( aPosStr, SCA_VALID | SCA_TAB_3D, pDocument, pDocument->GetAddressConvention() );
+ refPar->Get(2)->PutString( aPosStr );
+
+ // use link-update flag to prevent closing the document
+ // while the macro is running
+ BOOL bWasInLinkUpdate = pDocument->IsInLinkUpdate();
+ if ( !bWasInLinkUpdate )
+ pDocument->SetInLinkUpdate( TRUE );
+
+ if ( pCell )
+ pDocument->LockTable( rPos.Tab() );
+ SbxVariableRef refRes = new SbxVariable;
+ ErrCode eRet = pDocSh->CallBasic( aMacroStr, aBasicStr, NULL, refPar, refRes );
+ if ( pCell )
+ pDocument->UnlockTable( rPos.Tab() );
+
+ if ( !bWasInLinkUpdate )
+ pDocument->SetInLinkUpdate( FALSE );
+
+ // Eingabe abbrechen, wenn Basic-Makro FALSE zurueckgibt
+ if ( eRet == ERRCODE_NONE && refRes->GetType() == SbxBOOL && refRes->GetBool() == FALSE )
+ bRet = TRUE;
+ bDone = TRUE;
+ }
+ pSfxApp->LeaveBasicCall();
+
+ if ( !bDone && !pCell ) // Makro nicht gefunden (nur bei Eingabe)
+ {
+ //! andere Fehlermeldung, wenn gefunden, aber nicht bAllowed ??
+
+ ErrorBox aBox( pParent, WinBits(WB_OK),
+ ScGlobal::GetRscString( STR_VALID_MACRONOTFOUND ) );
+ aBox.Execute();
+ }
+
+ return bRet;
+}
+
+void ScValidationData::DoCalcError( ScFormulaCell* pCell ) const
+{
+ if ( eErrorStyle == SC_VALERR_MACRO )
+ DoMacro( pCell->aPos, EMPTY_STRING, pCell, NULL );
+}
+
+ // TRUE -> Abbruch
+
+BOOL ScValidationData::DoError( Window* pParent, const String& rInput,
+ const ScAddress& rPos ) const
+{
+ if ( eErrorStyle == SC_VALERR_MACRO )
+ return DoMacro( rPos, rInput, NULL, pParent );
+
+ // Fehlermeldung ausgeben
+
+ String aTitle = aErrorTitle;
+ if (!aTitle.Len())
+ aTitle = ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_0 ); // application title
+ String aMessage = aErrorMessage;
+ if (!aMessage.Len())
+ aMessage = ScGlobal::GetRscString( STR_VALID_DEFERROR );
+
+ //! ErrorBox / WarningBox / InfoBox ?
+ //! (bei InfoBox immer nur OK-Button)
+
+ WinBits nStyle = 0;
+ switch (eErrorStyle)
+ {
+ case SC_VALERR_STOP:
+ nStyle = WB_OK | WB_DEF_OK;
+ break;
+ case SC_VALERR_WARNING:
+ nStyle = WB_OK_CANCEL | WB_DEF_CANCEL;
+ break;
+ case SC_VALERR_INFO:
+ nStyle = WB_OK_CANCEL | WB_DEF_OK;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ MessBox aBox( pParent, WinBits(nStyle), aTitle, aMessage );
+ USHORT nRet = aBox.Execute();
+
+ return ( eErrorStyle == SC_VALERR_STOP || nRet == RET_CANCEL );
+}
+
+
+BOOL ScValidationData::IsDataValid( const String& rTest, const ScPatternAttr& rPattern,
+ const ScAddress& rPos ) const
+{
+ if ( eDataMode == SC_VALID_ANY )
+ return TRUE; // alles erlaubt
+
+ if ( rTest.GetChar(0) == '=' )
+ return FALSE; // Formeln sind sonst immer ungueltig
+
+ if ( !rTest.Len() )
+ return IsIgnoreBlank(); // leer: wie eingestellt
+
+ SvNumberFormatter* pFormatter = GetDocument()->GetFormatTable();
+
+ // Test, was es denn ist - wie in ScColumn::SetString
+
+ sal_uInt32 nFormat = rPattern.GetNumberFormat( pFormatter );
+
+ double nVal;
+ BOOL bIsVal = pFormatter->IsNumberFormat( rTest, nFormat, nVal );
+ ScBaseCell* pCell;
+ if (bIsVal)
+ pCell = new ScValueCell( nVal );
+ else
+ pCell = new ScStringCell( rTest );
+
+ BOOL bRet = IsDataValid( pCell, rPos );
+
+ pCell->Delete();
+ return bRet;
+}
+
+BOOL ScValidationData::IsDataValid( ScBaseCell* pCell, const ScAddress& rPos ) const
+{
+ if( eDataMode == SC_VALID_LIST )
+ return IsListValid( pCell, rPos );
+
+ double nVal = 0.0;
+ String aString;
+ BOOL bIsVal = TRUE;
+
+ switch (pCell->GetCellType())
+ {
+ case CELLTYPE_VALUE:
+ nVal = ((ScValueCell*)pCell)->GetValue();
+ break;
+ case CELLTYPE_STRING:
+ ((ScStringCell*)pCell)->GetString( aString );
+ bIsVal = FALSE;
+ break;
+ case CELLTYPE_EDIT:
+ ((ScEditCell*)pCell)->GetString( aString );
+ bIsVal = FALSE;
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
+ bIsVal = pFCell->IsValue();
+ if ( bIsVal )
+ nVal = pFCell->GetValue();
+ else
+ pFCell->GetString( aString );
+ }
+ break;
+ default: // Notizen, Broadcaster
+ return IsIgnoreBlank(); // wie eingestellt
+ }
+
+ BOOL bOk = TRUE;
+ switch (eDataMode)
+ {
+ // SC_VALID_ANY schon oben
+
+ case SC_VALID_WHOLE:
+ case SC_VALID_DECIMAL:
+ case SC_VALID_DATE: // Date/Time ist nur Formatierung
+ case SC_VALID_TIME:
+ bOk = bIsVal;
+ if ( bOk && eDataMode == SC_VALID_WHOLE )
+ bOk = ::rtl::math::approxEqual( nVal, floor(nVal+0.5) ); // ganze Zahlen
+ if ( bOk )
+ bOk = IsCellValid( pCell, rPos );
+ break;
+
+ case SC_VALID_CUSTOM:
+ // fuer Custom muss eOp == SC_COND_DIRECT sein
+ //! der Wert muss im Dokument stehen !!!!!!!!!!!!!!!!!!!!
+ bOk = IsCellValid( pCell, rPos );
+ break;
+
+ case SC_VALID_TEXTLEN:
+ bOk = !bIsVal; // nur Text
+ if ( bOk )
+ {
+ double nLenVal = (double) aString.Len();
+ ScValueCell aTmpCell( nLenVal );
+ bOk = IsCellValid( &aTmpCell, rPos );
+ }
+ break;
+
+ default:
+ DBG_ERROR("hammanochnich");
+ break;
+ }
+
+ return bOk;
+}
+
+// ----------------------------------------------------------------------------
+
+namespace {
+
+/** Token array helper. Iterates over all string tokens.
+ @descr The token array must contain separated string tokens only.
+ @param bSkipEmpty true = Ignores string tokens with empty strings. */
+class ScStringTokenIterator
+{
+public:
+ inline explicit ScStringTokenIterator( ScTokenArray& rTokArr, bool bSkipEmpty = true ) :
+ mrTokArr( rTokArr ), mbSkipEmpty( bSkipEmpty ), mbOk( true ) {}
+
+ /** Returns the string of the first string token or NULL on error or empty token array. */
+ const String* First();
+ /** Returns the string of the next string token or NULL on error or end of token array. */
+ const String* Next();
+
+ /** Returns false, if a wrong token has been found. Does NOT return false on end of token array. */
+ inline bool Ok() const { return mbOk; }
+
+private:
+ ScTokenArray& mrTokArr; /// The token array for iteration.
+ bool mbSkipEmpty; /// Ignore empty strings.
+ bool mbOk; /// true = correct token or end of token array.
+};
+
+const String* ScStringTokenIterator::First()
+{
+ mrTokArr.Reset();
+ mbOk = true;
+ return Next();
+}
+
+const String* ScStringTokenIterator::Next()
+{
+ if( !mbOk )
+ return NULL;
+
+ // seek to next non-separator token
+ const FormulaToken* pToken = mrTokArr.NextNoSpaces();
+ while( pToken && (pToken->GetOpCode() == ocSep) )
+ pToken = mrTokArr.NextNoSpaces();
+
+ mbOk = !pToken || (pToken->GetType() == formula::svString);
+ const String* pString = (mbOk && pToken) ? &pToken->GetString() : NULL;
+ // string found but empty -> get next token; otherwise return it
+ return (mbSkipEmpty && pString && !pString->Len()) ? Next() : pString;
+}
+
+// ----------------------------------------------------------------------------
+
+/** Returns the number format of the passed cell, or the standard format. */
+ULONG lclGetCellFormat( ScDocument& rDoc, const ScAddress& rPos )
+{
+ const ScPatternAttr* pPattern = rDoc.GetPattern( rPos.Col(), rPos.Row(), rPos.Tab() );
+ if( !pPattern )
+ pPattern = rDoc.GetDefPattern();
+ return pPattern->GetNumberFormat( rDoc.GetFormatTable() );
+}
+
+/** Inserts the passed string object. Always takes ownership. pData is invalid after this call! */
+void lclInsertStringToCollection( TypedScStrCollection& rStrColl, TypedStrData* pData, bool bSorted )
+{
+ if( !(bSorted ? rStrColl.Insert( pData ) : rStrColl.AtInsert( rStrColl.GetCount(), pData )) )
+ delete pData;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+bool ScValidationData::HasSelectionList() const
+{
+ return (eDataMode == SC_VALID_LIST) && (mnListType != ValidListType::INVISIBLE);
+}
+
+bool ScValidationData::GetSelectionFromFormula( TypedScStrCollection* pStrings,
+ ScBaseCell* pCell,
+ const ScAddress& rPos,
+ const ScTokenArray& rTokArr,
+ int& rMatch ) const
+{
+ bool bOk = true;
+
+ // pDoc is private in condition, use an accessor and a long winded name.
+ ScDocument* pDocument = GetDocument();
+ if( NULL == pDocument )
+ return false;
+
+ ScFormulaCell aValidationSrc( pDocument, rPos, &rTokArr,
+ formula::FormulaGrammar::GRAM_DEFAULT, MM_FORMULA);
+
+ // Make sure the formula gets interpreted and a result is delivered,
+ // regardless of the AutoCalc setting.
+ aValidationSrc.Interpret();
+
+ ScMatrixRef xMatRef;
+ const ScMatrix *pValues = aValidationSrc.GetMatrix();
+ if (!pValues)
+ {
+ // The somewhat nasty case of either an error occured, or the
+ // dereferenced value of a single cell reference or an immediate result
+ // is stored as a single value.
+
+ // Use an interim matrix to create the TypedStrData below.
+ xMatRef = new ScMatrix(1,1);
+
+ USHORT nErrCode = aValidationSrc.GetErrCode();
+ if (nErrCode)
+ {
+ /* TODO : to use later in an alert box?
+ * String rStrResult = "...";
+ * rStrResult += ScGlobal::GetLongErrorString(nErrCode);
+ */
+
+ xMatRef->PutError( nErrCode, 0);
+ bOk = false;
+ }
+ else if (aValidationSrc.HasValueData())
+ xMatRef->PutDouble( aValidationSrc.GetValue(), 0);
+ else
+ {
+ String aStr;
+ aValidationSrc.GetString( aStr);
+ xMatRef->PutString( aStr, 0);
+ }
+
+ pValues = xMatRef;
+ }
+
+ // which index matched. We will want it eventually to pre-select that item.
+ rMatch = -1;
+
+ SvNumberFormatter* pFormatter = GetDocument()->GetFormatTable();
+
+ bool bSortList = (mnListType == ValidListType::SORTEDASCENDING);
+ SCSIZE nCol, nRow, nCols, nRows, n = 0;
+ pValues->GetDimensions( nCols, nRows );
+
+ /* XL artificially limits things to a single col or row in the UI but does
+ * not list the constraint in MOOXml. If a defined name or INDIRECT
+ * resulting in 1D is entered in the UI and the definition later modified
+ * to 2D, it is evaluated fine and also stored and loaded. Lets get ahead
+ * of the curve and support 2d. In XL, values are listed row-wise, do the
+ * same. */
+ for( nRow = 0; nRow < nRows ; nRow++ )
+ {
+ for( nCol = 0; nCol < nCols ; nCol++ )
+ {
+ ScTokenArray aCondTokArr;
+ TypedStrData* pEntry = NULL;
+ ScMatValType nMatValType;
+ String aValStr;
+ const ScMatrixValue* pMatVal = pValues->Get( nCol, nRow, nMatValType);
+
+ // strings and empties
+ if( NULL == pMatVal || ScMatrix::IsNonValueType( nMatValType ) )
+ {
+ if( NULL != pMatVal )
+ aValStr = pMatVal->GetString();
+
+ if( NULL != pStrings )
+ pEntry = new TypedStrData( aValStr, 0.0, SC_STRTYPE_STANDARD);
+
+ if( pCell && rMatch < 0 )
+ aCondTokArr.AddString( aValStr );
+ }
+ else
+ {
+ USHORT nErr = pMatVal->GetError();
+
+ if( 0 != nErr )
+ {
+ aValStr = ScGlobal::GetErrorString( nErr );
+ }
+ else
+ {
+ // FIXME FIXME FIXME
+ // Feature regression. Date formats are lost passing through the matrix
+ pFormatter->GetInputLineString( pMatVal->fVal, 0, aValStr );
+ }
+
+ if( pCell && rMatch < 0 )
+ {
+ // I am not sure errors will work here, but a user can no
+ // manually enter an error yet so the point is somewhat moot.
+ aCondTokArr.AddDouble( pMatVal->fVal );
+ }
+ if( NULL != pStrings )
+ pEntry = new TypedStrData( aValStr, pMatVal->fVal, SC_STRTYPE_VALUE);
+ }
+
+ if( rMatch < 0 && NULL != pCell && IsEqualToTokenArray( pCell, rPos, aCondTokArr ) )
+ {
+ rMatch = n;
+ // short circuit on the first match if not filling the list
+ if( NULL == pStrings )
+ return true;
+ }
+
+ if( NULL != pEntry )
+ {
+ lclInsertStringToCollection( *pStrings, pEntry, bSortList );
+ n++;
+ }
+ }
+ }
+
+ // In case of no match needed and an error occurred, return that error
+ // entry as valid instead of silently failing.
+ return bOk || NULL == pCell;
+}
+
+bool ScValidationData::FillSelectionList( TypedScStrCollection& rStrColl, const ScAddress& rPos ) const
+{
+ bool bOk = false;
+
+ if( HasSelectionList() )
+ {
+ ::std::auto_ptr< ScTokenArray > pTokArr( CreateTokenArry( 0 ) );
+
+ // *** try if formula is a string list ***
+
+ bool bSortList = (mnListType == ValidListType::SORTEDASCENDING);
+ UINT32 nFormat = lclGetCellFormat( *GetDocument(), rPos );
+ ScStringTokenIterator aIt( *pTokArr );
+ for( const String* pString = aIt.First(); pString && aIt.Ok(); pString = aIt.Next() )
+ {
+ double fValue;
+ bool bIsValue = GetDocument()->GetFormatTable()->IsNumberFormat( *pString, nFormat, fValue );
+ TypedStrData* pData = new TypedStrData( *pString, fValue, bIsValue ? SC_STRTYPE_VALUE : SC_STRTYPE_STANDARD );
+ lclInsertStringToCollection( rStrColl, pData, bSortList );
+ }
+ bOk = aIt.Ok();
+
+ // *** if not a string list, try if formula results in a cell range or
+ // anything else we recognize as valid ***
+
+ if (!bOk)
+ {
+ int nMatch;
+ bOk = GetSelectionFromFormula( &rStrColl, NULL, rPos, *pTokArr, nMatch );
+ }
+ }
+
+ return bOk;
+}
+
+// ----------------------------------------------------------------------------
+
+bool ScValidationData::IsEqualToTokenArray( ScBaseCell* pCell, const ScAddress& rPos, const ScTokenArray& rTokArr ) const
+{
+ // create a condition entry that tests on equality and set the passed token array
+ ScConditionEntry aCondEntry( SC_COND_EQUAL, &rTokArr, NULL, GetDocument(), rPos );
+ return aCondEntry.IsCellValid( pCell, rPos );
+}
+
+bool ScValidationData::IsListValid( ScBaseCell* pCell, const ScAddress& rPos ) const
+{
+ bool bIsValid = false;
+
+ /* Compare input cell with all supported tokens from the formula.
+ Currently a formula may contain:
+ 1) A list of strings (at least one string).
+ 2) A single cell or range reference.
+ 3) A single defined name (must contain a cell/range reference, another
+ name, or DB range, or a formula resulting in a cell/range reference
+ or matrix/array).
+ 4) A single database range.
+ 5) A formula resulting in a cell/range reference or matrix/array.
+ */
+
+ ::std::auto_ptr< ScTokenArray > pTokArr( CreateTokenArry( 0 ) );
+
+ // *** try if formula is a string list ***
+
+ UINT32 nFormat = lclGetCellFormat( *GetDocument(), rPos );
+ ScStringTokenIterator aIt( *pTokArr );
+ for( const String* pString = aIt.First(); pString && aIt.Ok(); pString = aIt.Next() )
+ {
+ /* Do not break the loop, if a valid string has been found.
+ This is to find invalid tokens following in the formula. */
+ if( !bIsValid )
+ {
+ // create a formula containing a single string or number
+ ScTokenArray aCondTokArr;
+ double fValue;
+ if( GetDocument()->GetFormatTable()->IsNumberFormat( *pString, nFormat, fValue ) )
+ aCondTokArr.AddDouble( fValue );
+ else
+ aCondTokArr.AddString( *pString );
+
+ bIsValid = IsEqualToTokenArray( pCell, rPos, aCondTokArr );
+ }
+ }
+
+ if( !aIt.Ok() )
+ bIsValid = false;
+
+ // *** if not a string list, try if formula results in a cell range or
+ // anything else we recognize as valid ***
+
+ if (!bIsValid)
+ {
+ int nMatch;
+ bIsValid = GetSelectionFromFormula( NULL, pCell, rPos, *pTokArr, nMatch );
+ bIsValid = bIsValid && nMatch >= 0;
+ }
+
+ return bIsValid;
+}
+
+// ============================================================================
+// ============================================================================
+
+ScValidationDataList::ScValidationDataList(const ScValidationDataList& rList) :
+ ScValidationEntries_Impl()
+{
+ // fuer Ref-Undo - echte Kopie mit neuen Tokens!
+
+ USHORT nCount = rList.Count();
+
+ for (USHORT i=0; i<nCount; i++)
+ InsertNew( rList[i]->Clone() );
+
+ //! sortierte Eintraege aus rList schneller einfuegen ???
+}
+
+ScValidationDataList::ScValidationDataList(ScDocument* pNewDoc,
+ const ScValidationDataList& rList)
+{
+ // fuer neues Dokument - echte Kopie mit neuen Tokens!
+
+ USHORT nCount = rList.Count();
+
+ for (USHORT i=0; i<nCount; i++)
+ InsertNew( rList[i]->Clone(pNewDoc) );
+
+ //! sortierte Eintraege aus rList schneller einfuegen ???
+}
+
+ScValidationData* ScValidationDataList::GetData( sal_uInt32 nKey )
+{
+ //! binaer suchen
+
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ if ((*this)[i]->GetKey() == nKey)
+ return (*this)[i];
+
+ DBG_ERROR("ScValidationDataList: Eintrag nicht gefunden");
+ return NULL;
+}
+
+void ScValidationDataList::ResetUsed()
+{
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ (*this)[i]->SetUsed(FALSE);
+}
+
+void ScValidationDataList::CompileXML()
+{
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ (*this)[i]->CompileXML();
+}
+
+void ScValidationDataList::UpdateReference( UpdateRefMode eUpdateRefMode,
+ const ScRange& rRange, SCsCOL nDx, SCsROW nDy, SCsTAB nDz )
+{
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ (*this)[i]->UpdateReference( eUpdateRefMode, rRange, nDx, nDy, nDz);
+}
+
+void ScValidationDataList::UpdateMoveTab( SCTAB nOldPos, SCTAB nNewPos )
+{
+ USHORT nCount = Count();
+ for (USHORT i=0; i<nCount; i++)
+ (*this)[i]->UpdateMoveTab( nOldPos, nNewPos );
+}
+
+bool ScValidationDataList::MarkUsedExternalReferences() const
+{
+ bool bAllMarked = false;
+ USHORT nCount = Count();
+ for (USHORT i=0; !bAllMarked && i<nCount; i++)
+ bAllMarked = (*this)[i]->MarkUsedExternalReferences();
+ return bAllMarked;
+}
+
+BOOL ScValidationDataList::operator==( const ScValidationDataList& r ) const
+{
+ // fuer Ref-Undo - interne Variablen werden nicht verglichen
+
+ USHORT nCount = Count();
+ BOOL bEqual = ( nCount == r.Count() );
+ for (USHORT i=0; i<nCount && bEqual; i++) // Eintraege sind sortiert
+ if ( !(*this)[i]->EqualEntries(*r[i]) ) // Eintraege unterschiedlich ?
+ bEqual = FALSE;
+
+ return bEqual;
+}
+